Python vars () глобальная ошибка имени - PullRequest
3 голосов
/ 09 февраля 2010

У меня возникли некоторые проблемы с пониманием, что происходит со следующей функцией:

def ness():
 pie='yum'
 vars()[pie]=4
 print vars()[pie]
 print yum

Итак, когда я бегу, я получаю такой результат:

>>> 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

Если я не пишу это как функцию, а просто набираю ее в командной строке по одной строке, она работает нормально, например:

>>> pie='yum'
>>> vars()[pie]=4
>>> print vars()[pie]
4
>>> print yum
4
>>> 

Edit: Предположим, я хотел сделать вещи немного более сложными, чем это, и вместо того, чтобы устанавливать значение yum и печатать это значение, я определяю некоторые функции и хочу вызвать одну из них на основе некоторого ввода:

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'

Поэтому, когда я звоню ness, я получаю ключевую ошибку:

>>> ness(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in ness
KeyError: 'p'

Теперь я знаю, что могу делать такие вещи с некоторыми утверждениями elif, но мне интересно, будет ли это работать тоже, и если использование bisect, как это, будет более эффективным (скажем, если мне нужно проверить 1000 значений choo) чем использование elifs.

Большое спасибо за помощь.

Ответы [ 5 ]

4 голосов
/ 09 февраля 2010

vars() внутри функции дает вам локальное пространство имен, как и locals() - см. документы .Вне функции (например, по приглашению) locals() (и, конечно, vars()) дает глобальное пространство имен модуля, как и globals().Как говорят в документах , попытка присвоения локальной переменной функции с помощью locals() (или, эквивалентно, vars() внутри функции) не поддерживается в Python.Если вы хотите присвоить глобальную переменную, как вы это делаете, когда вы в приглашении (или иным образом вне функции), используйте globals() вместо vars() (возможно, не самый чистый подход- глобальные переменные по понятным причинам осуждаются - но это работает).

2 голосов
/ 09 февраля 2010

Есть способ сделать это с помощью exec

>>> def ness():
...  pie='yum'
...  exec pie+"=4"
...  print vars()[pie]
...  print yum
...
>>>
>>> ness()
4
4

Но вместо этого использование нового dict лучше и безопаснее

>>> def ness():
...  dic={}
...  pie='yum'
...  dic[pie]=4
...  print dic[pie]
...  print dic['yum']
...
>>> ness()
4
4
>>>
1 голос
/ 09 февраля 2010

Это небезопасно , чтобы изменить dict, возвращаемый vars ()

вары ([объект]) ¶

Без аргументов действуйте как localals ().

С модулем, классом или объектом экземпляра класса в качестве аргумента (или все остальное, что имеет dict атрибут), вернуть этот атрибут.

Примечание

Возвращаемый словарь не должен изменяться: влияние на соответствующие таблицы символов не определено.

Ваш второй пример - особый случай. vars() эквивалентно globals() в глобальном пространстве имен, а диктант, возвращаемый globals(), ведет себя так, как вы ожидаете (но осуждает)

>>> id(vars()),id(globals())
(3085426868L, 3085426868L)
0 голосов
/ 09 февраля 2010

[Редактировать: я должен быть неправ здесь, так как пример 'exec' работает.]

Как все отмечают, модифицировать vars () - плохая идея. Однако вы можете понять ошибку, осознав, что python в некотором смысле не «видит», что «yum» является локальным. «print yum» все еще разрешается как глобальная ссылка; это происходит перед выполнением любого кода.

По той же причине вы получаете UnboundLocalError от:

>>> 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
0 голосов
/ 09 февраля 2010

vars() эквивалентно locals(), что в случае функции является локальными переменными в ее области видимости и в интерактивном интерпретаторе в той области, в которой она у вас есть, vars() is globals(). locals() только для чтения; последствия попытки изменить его не определены (и на практике просто не работают). globals() можно изменить, но вы все же никогда не должны прямо вводить что-либо в диктовку, которую он возвращает.

...