[Tutor] Class and Scope Question

Rich Krauter rmkrauter at yahoo.com
Fri May 6 14:07:13 CEST 2005


Tim Johnson wrote:
> The following test script is kind of got me baffled:
> #!/usr/local/bin/python
> class Eval:
>     def __getitem__(self,key):
>         return eval(key)
> ##def test():
> ##  i = 100
> ##  b = ["My", "name", "is", "Tim"]
> ##  test = "this is number %(str(i))s for a test %(' '.join(b))s"
> ##  s = test % Eval()
> ##  print s
> ##test()
> i = 100
> b = ["My", "name", "is", "Tim"]
> test = "this is number %(str(i))s for a test %(' '.join(b))s"
> print test % Eval()
> ## ============================================================
> Running this gives me the following :
> [tim at linus baker]$ python test.py
> this is number 100 for a test My name is Tim
> ## cool!
> Now if I comment out the last four lines and uncomment
> the previous 7, I get the following error message:
> [tim at linus baker]$ python test.py
> Traceback (most recent call last):
>   File "test.py", line 11, in ?
>     test()
>   File "test.py", line 9, in test
>     s = test % Eval()
>   File "test.py", line 4, in __getitem__
>     return eval(key)
>   File "<string>", line 0, in ?
> NameError: name 'i' is not defined
> ## It's been a lloooonngg day. What am I missing here?
> Explanation and solution is no doubt going to further edify
> me about python.
> 
> TIA
> tim
> 

Tim,

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 has a more 
general solution in the comments at the bottom. Basically, you need to 
put an __init__ in the Eval class, pass locals() and globals() to it, 
and use those passed-in values in your call to the eval() built-in.

I believe the result you see is due to python's lexical scoping rules. 
Scope is determined by a function- or class-definition's position in the 
text of the program.

<example>

def f():
     x = 20
     def g():
         print x
     g()

def h():
     x = 50
     i()

def i():
     print x

if __name__ == '__main__':
     f() # works
     h() # doesn't work

</example>

Here's another example:

<example>
g = 'module level'

class A:
     def print_locals_and_globals(self):
         for k,v in locals().items()+globals().items():
             print k,v

def func():
     # a couple names that won't appear
     # in a's locals or globals
     i = 10
     s = 'a string'

     a = A()
     a.print_locals_and_globals()

if __name__ == '__main__':
     func()

</example>

So it seems the locals and globals visible to an instance of a class is 
determined by where the class is defined, not by where the instance is 
created.

HTH,

Rich


More information about the Tutor mailing list