Python vars() global name error
I'm having a bit of trouble understanding what's going wrong with the following function:
def ness():
pie='yum'
vars()[pie]=4
print vars()[pie]
print yum
So When I run that I get this result:
>>> ness()
4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in ness
NameError: global name 'yum' is not defined
If I don't write it as a function and just type it in on the command line one line at a time it works fine, like so:
>>> pie='yum'
>>> vars()[pie]=4
>>> print vars()[pie]
4
>>> print yum
4
>>>
Edit: Suppose I wanted to make things a bit more complicated than this and instead of setting yum to a value and printing that value, I define some functions, and want to call one of them based on some input:
def ness(choo):
dic={}
dessert=()
dnum=[10,100]
desserts='pie'
dic[dessert]=str(desserts[bisect(dnum,choo)])
vars()[dic[dessert]]()
def p():
print 'ummmm ummm'
def i():
print 'hooo aaaaa'
def e():
print 'woooo'
So when I call ness I get a key error:
>>&g开发者_如何学Got; ness(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in ness
KeyError: 'p'
Now I know I can do things like this with some elif statements, but I'm wondering if this would work too, and if using bisect like this would be more efficient (say if i need to check 1000 values of choo) than using elifs.
Thanks much for the assistance.
vars()
within a function gives you the local namespace, just like locals()
-- see the docs. Outside of a function (e.g. at the prompt) locals()
(and vars()
of course) gives you the module's global namespace, just like globals()
. As the docs say, trying to assign to a function's local variable through locals()
(or equivalently, vars()
inside a function) is not supported in Python. If you want to assign to a global variable, as you do when you're at the prompt (or otherwise outside of a function), use globals()
instead of vars()
(maybe not the cleanest approach -- global variables are understandably frowned upon -- but it does work).
There is way to do it with exec
>>> def ness():
... pie='yum'
... exec pie+"=4"
... print vars()[pie]
... print yum
...
>>>
>>> ness()
4
4
But Instead of doing that, using a new dict is better and safe
>>> def ness():
... dic={}
... pie='yum'
... dic[pie]=4
... print dic[pie]
... print dic['yum']
...
>>> ness()
4
4
>>>
It's not safe to modify the dict returned by vars()
vars([object])¶
Without an argument, act like locals().
With a module, class or class instance object as argument (or anything else that has a dict attribute), return that attribute.
Note
The returned dictionary should not be modified: the effects on the corresponding symbol table are undefined.
Your second example is a special case. vars()
is equivalent to globals()
in the global namespace, and the dict returned by globals()
behaves as you would expect ( but is frowned upon )
>>> id(vars()),id(globals())
(3085426868L, 3085426868L)
vars()
is equivalent to locals()
, which in the case of the function is the local variables in its scope and at in the interactive interpreter at the scope you have it, vars() is globals()
. locals()
is for reading only; the effects of trying to change it are undefined (and in practice, just doesn't work). globals()
can be modified, but you still should never directly put anything in the dict it returns.
[Edit: I must be wrong here, since the 'exec' example works.]
As everyone points out, it's a bad idea to modify vars(). You can understand the error, though, by realizing that python in some sense doesn't "see" that "yum" is a local. "print yum" is still resolved as a global reference; this happens before any code is executed.
It's the same reason you get an UnboundLocalError from:
>>> y = 100
>>> def foo(x):
... if x == 1:
... y = 10
... print y
...
>>> foo(1)
10
>>> foo(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in foo
UnboundLocalError: local variable 'y' referenced before assignment
精彩评论