scope question in a switch mixin

browerg at verizon.net browerg at verizon.net
Fri Jan 11 10:19:05 EST 2008


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[i], vals[i], 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)





More information about the Python-list mailing list