В чем разница между globals(), locals()и vars()? Что они возвращают? Полезны ли обновления результатов?
В чем разница между globals(), locals()и vars()? Что они возвращают? Полезны ли обновления результатов?
Ответы:
Каждый из них возвращает словарь:
globals() всегда возвращает словарь пространства имен модуляlocals() всегда возвращает в словарь в текущем пространстве именvars()возвращается либо в словаре текущего пространства имен (если вызывается без аргументов) , или в словаре аргумента.localsи varsмог бы использовать еще несколько объяснений. Если locals()вызывается внутри функции, он обновляет dict значениями текущего пространства имен локальной переменной (плюс любые переменные замыкания) на тот момент и возвращает его. Несколько вызовов locals()в одном и том же фрейме стека каждый раз возвращают один и тот же dict - он присоединяется к объекту фрейма стека в качестве его f_localsатрибута. Содержимое диктовки обновляется при каждом locals()вызове и каждом f_localsдоступе к атрибуту, но только при таких вызовах или доступах к атрибутам. Он не обновляется автоматически при назначении переменных, и назначение записей в dict не будет назначать соответствующие локальные переменные:
import inspect
def f():
x = 1
l = locals()
print(l)
locals()
print(l)
x = 2
print(x, l['x'])
l['x'] = 3
print(x, l['x'])
inspect.currentframe().f_locals
print(x, l['x'])
f()
дает нам:
{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2
Первый print(l)показывает только 'x'запись, потому что назначение lпроисходит после locals()вызова. Второй print(l)после locals()повторного вызова показывает lзапись, хотя мы не сохранили возвращаемое значение. Третий и четвертый printэтапы показывают, что присвоение переменных не обновляется, lи наоборот, но после того, как мы f_localsполучили доступ , локальные переменные копируются locals()снова.
Две заметки:
exec "pass"строку в функцию. Это переключает функцию в более старый, более медленный режим выполнения, который использует locals()dict как каноническое представление локальных переменных.Если locals()вызывается вне функции, он возвращает фактический словарь, который является текущим пространством имен. Дальнейшие изменения в пространстве имен будут отражены в словаре, и изменения в словаре будут отражены в пространстве имен:
class Test(object):
a = 'one'
b = 'two'
huh = locals()
c = 'three'
huh['d'] = 'four'
print huh
дает нам:
{
'a': 'one',
'b': 'two',
'c': 'three',
'd': 'four',
'huh': {...},
'__module__': '__main__',
}
Пока что все, о чем я говорил, locals()также верно для vars()... вот в чем разница: vars()принимает один объект в качестве аргумента, и если вы даете ему объект, он возвращает значение __dict__этого объекта. Для типичного объекта __dict__именно там хранится большая часть его атрибутных данных. Это включает переменные класса и глобальные переменные модуля:
class Test(object):
a = 'one'
b = 'two'
def frobber(self):
print self.c
t = Test()
huh = vars(t)
huh['c'] = 'three'
t.frobber()
что дает нам:
three
Обратите внимание, что функция - __dict__это пространство имен ее атрибутов, а не локальные переменные. Для функций не имеет смысла __dict__хранить локальные переменные, поскольку рекурсия и многопоточность означают, что может быть несколько вызовов функции одновременно, каждый из которых имеет свои собственные локальные переменные:
def f(outer):
if outer:
f(False)
print('Outer call locals:', locals())
print('f.__dict__:', f.__dict__)
else:
print('Inner call locals:', locals())
print('f.__dict__:', f.__dict__)
f.x = 3
f(True)
что дает нам:
Inner call locals: {'outer': False}
f.__dict__: {'x': 3}
Outer call locals: {'outer': True}
f.__dict__: {'x': 3}
Здесь fвызывает себя рекурсивно, поэтому внутренние и внешние вызовы перекрываются. Каждый из них видит свои локальные переменные при вызове locals(), но оба вызова видят одно f.__dict__и то же , и в нем f.__dict__нет локальных переменных.
vars()или locals()словарь, вызываемый внутри функции, если вы используете eval(). EG: def test(): huh = locals(); huh['d'] = 4; print eval('d')печатает 4, когда test()выполняется!
dict(возвращаемое locals()) оказывается отраженным в локальном пространстве имен, а изменения в локальном пространстве имен отражаются в dict(в моем python). Единственное, что спецификация не гарантирует такое поведение.
import thisи в Googlesite:docs.python.org namespace