У чому різниця між globals(), locals()і vars()? Що вони повертають? Чи корисні оновлення результатів?
У чому різниця між globals(), locals()і vars()? Що вони повертають? Чи корисні оновлення результатів?
Відповіді:
Кожен із них повертає словник:
globals() завжди повертає словник простору імен модуляlocals() завжди повертає в словник в поточному просторі іменvars()повертається або в словнику поточного простору імен (якщо викликається без аргументів) , або в словнику аргументу.localsі varsмогло б використати ще одне пояснення. Якщо locals()викликається всередині функції, він оновлює дікт зі значеннями поточної локальної області змінних імен (плюс будь-які змінні закриття) на цей момент і повертає її. Кілька викликів locals()в одному кадрі стека щоразу повертають один і той же дікт - він додається до об'єкта кадру стека як його f_localsатрибут. Вміст диктанту оновлюється під час кожного locals()виклику та f_localsдоступу до кожного атрибута, але лише на таких зверненнях або атрибутах. Він не оновлюється автоматично, коли присвоюються змінні, і при призначенні записів у дикті не буде призначено відповідних локальних змінних:
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(у моєму пітоні). Єдине, що специфікація не гарантує такої поведінки.
import thisі в googlesite:docs.python.org namespace