scope question in a switch mixin

G

Guest

The code that follows is the result of noodling around with switches as a learning tool. I've played with python for a few years, but I'm self-taught, so . . .

Class Switch builds a set of functions. Method switch executes one of them given a value of the switch variable.

My question is, why are modules imported at the top of the program not visible to the functions Switch builds? There is
no problem when the import is in the function, but I thought initially that imports at the top would be in its globals.

The import that works is at line 111 in the code.

Thanks in advance!

George

'''Mixin Switch provides function switch(key) that executes an appropriate function.

Each instance can: use a different switch variable.
be used as many places in a program as desirable.
be changed in one place, no matte how many places it is used.

Usage: inst = Switch(keys, vals, base)
whose arguments are sequenes:
keys has switch values ('su', 'mo', . . .),
base has the shared fore and aft parts of instance functions, and
vals has the individual parts of instane functions.

Example: Suppose you want to switch on days of the week:
keys = ('su', 'mo', 'tu', 'we', 'th', 'fr', 'sa', 'de')
vals = ('Sunday is Comic-day.', 'Monday is Moan-day.',
'Tuesday is Twos-day.', 'Wednesday is Hump-day.',
'Thursday is Shop-day.', 'Friday is TGIF-day.',
'Saturday is Food-day.', 'Anything else is Party-day!')
fore = "def %s(self, *args):\n\tprint '"
aft = "'\\n"

produces functions of the form:
def su(self, *args):\\n\\tprint 'Sunday is Comic-day.'\\n
or, for humans:
def su(self, *args):
print 'Sunday is Comic-day.'

Test code (below) for this example produces:
Sunday is Comic-day.
Monday is Moan-day.
. . .
Anything else is Party-day!
key {} <type 'dict'> keys must be hashable (immutable) objects.

Example: Suppose you want to swith on a function and its argument.
Test code (below) returns calculated values using functions like:
def %s(self, *args):\\n\\timport math\\n\\ttmp = (args[0] / math.pi)\\n\\treturn tmp\\n
or, for humans:
def %s(self, *args):
import math
tmp = (args[0] / math.pi)
return tmp
that produce:
In toplevel: circ.switch(dC, 10), d = 3.18309886184
In toplevel: circ.switch(Cd, 3.18), C = 9.99026463842
In toplevel: circ.switch(rC, 5), r = 0.795774715459
In toplevel: circ.switch(Cr, 0.796), C = 5.00141550451
In toplevel: circ.switch(A , 5), A = 78.5398163397

Thanks to Jean-Paul Calderone for his post at
http://mail.python.org/pipermail/python-list/2007-June/446648.html
in response to a question by vasudevrama t
http://mail.python.org/pipermail/python-list/2007-June/446618.html
'''

#import math

class Switch(object):

def __init__(self, keys, vals, base):
self.dictionary = {}
tmpd = {}
for i in range(len(vals)):
func = ''.join([base[0] % keys, vals, base[1]])
compile(func, '<stderr>', 'exec')
exec(func, tmpd)
for k, v in tmpd.items():
if k in keys:
self.dictionary[k] = v

def switch(self, key, *args, **kwargs):
try:
result = self.dictionary[key](self, *args, **kwargs)
except KeyError:
result = self.dictionary['de'](self, *args, **kwargs)
return result

if '__main__' == __name__:
'''Case 1: execute a statement.
'''
keys = ('su', 'mo', 'tu', 'we', 'th', 'fr', 'sa', 'de')
vals = ('Sunday is Comic-day.', 'Monday is Moan-day.',
'Tuesday is Twos-day.', 'Wednesday is Hump-day.',
'Thursday is Shop-day.', 'Friday is TGIF-day.',
'Saturday is Food-day.', 'Anything else is Party-day!')
fore = "def %s(self, *args):\n\tprint '"
aft = "'\n"
base = (fore, aft)
day = Switch(keys, vals, base)
for k in keys:
try:
day.switch(k)
except TypeError:
print 'key %s %s keys must be hashable (immutable) objects.' % (k, type(k))
for k in ('xx', 1234, 12.3, {}):
try:
day.switch(k)
except TypeError:
print 'key %s %s keys must be hashable (immutable) objects.' % (k, type(k))

'''Case 2: execute an expression.
'''
keys = ('dC', 'Cd', 'rC', 'Cr', 'A', 'de')
vals = ("(args[0] / math.pi)", # diameter given Circumference
"(math.pi * args[0])", # Circumferene given diameter
"(args[0] / (2 * math.pi))", # radius given Circumference
"(2 * math.pi * args[0])", # Circumference given radius
"(math.pi * args[0]**2)", # Area given radius
"False")
# Why are modules imported at the top not found in these functions?
fore = "def %s(self, *args):\n\timport math\n\ttmp = "
aft = "\n\treturn tmp\n"
base = (fore, aft)
circ = Switch(keys, vals, base)
vs = (10, 3.18, 5, 0.796, 5)
kvs = zip(keys, vs)
for k, v in kvs:
result = circ.switch(k, v)
print "In toplevel: circ.switch(%-2s, %5s), %s = %s" % (k, v, k[0], result)
 
J

John Machin

The code that follows is the result of noodling around with switches as a learning tool. I've played with python for a few years, but I'm self-taught, so . . .

Class Switch builds a set of functions. Method switch executes one of them given a value of the switch variable.

My question is, why are modules imported at the top of the program not visible to the functions Switch builds? There is
no problem when the import is in the function, but I thought initially that imports at the top would be in its globals.

The global namespace of the to-be-exec'ed code is the dictionary that
you supply. That dictionary doesn't contain "math". More comments below.

[snip]
#import math

class Switch(object):

def __init__(self, keys, vals, base):
self.dictionary = {}
tmpd = {}

Uncomment the above import, remove the import from your constructed
source code and try
tmpd = {'math': math}
for i in range(len(vals)):
func = ''.join([base[0] % keys, vals, base[1]])
compile(func, '<stderr>', 'exec')
exec(func, tmpd)


compile returns a code object, which you are throwing away. Comment out
that statement, and the behaviour of your code will not change. This is
because if the first argument to exec is a string, it is compiled into a
code object.

It's a long time since exec has been documented as a *function*. Why?
Because it isn't:
File "<stdin>", line 1
foo = exec
^
SyntaxError: invalid syntax
What book/tutorial did you get that from?

Cheers,
John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top