Jaka jest różnica między globals(), locals()i vars()? Co oni zwracają? Czy aktualizacje wyników są przydatne?
Jaka jest różnica między globals(), locals()i vars()? Co oni zwracają? Czy aktualizacje wyników są przydatne?
Odpowiedzi:
Każdy z nich zwraca słownik:
globals() zawsze zwraca słownik przestrzeni nazw modułulocals() Zawsze wraca do słownika bieżącej przestrzeni nazwvars()powraca albo słownika bieżącej przestrzeni nazw (jeśli wywołana bez argumentów) lub w słowniku argumentu.localsi varsprzydałoby się więcej wyjaśnień. Jeśli locals()jest wywoływana wewnątrz funkcji, aktualizuje dict o wartości bieżącej przestrzeni nazw zmiennej lokalnej (plus wszelkie zmienne zamykające) na ten moment i zwraca ją. Wielokrotne wywołania locals()w tej samej ramce stosu za każdym razem zwracają ten sam dykt - jest on dołączony do obiektu ramki stosu jako jego f_localsatrybut. Zawartość dyktu jest aktualizowana przy każdym locals()wywołaniu i każdym f_localsdostępie do atrybutu, ale tylko przy takich wywołaniach lub dostępach do atrybutów. Nie aktualizuje się automatycznie po przypisaniu zmiennych, a przypisanie wpisów w dict nie spowoduje przypisania odpowiednich zmiennych lokalnych:
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()
daje nam:
{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2
Pierwsza print(l)pokazuje tylko 'x'wpis, ponieważ przypisanie do lnastępuje po locals()wywołaniu. Drugi print(l), po locals()ponownym wywołaniu , pokazuje lwpis, mimo że nie zapisaliśmy wartości zwracanej. Trzeci i czwarty printpokazują, że przypisywanie zmiennych nie aktualizuje się li odwrotnie, ale po uzyskaniu dostępu f_localszmienne lokalne są locals()ponownie kopiowane do .
Dwie uwagi:
exec "pass"linię do funkcji. Powoduje to przełączenie funkcji do starszego, wolniejszego trybu wykonywania, w którym locals()dict jest kanoniczną reprezentacją zmiennych lokalnych.Jeśli locals()jest wywoływana poza funkcją, zwraca rzeczywisty słownik, który jest bieżącą przestrzenią nazw. Dalsze zmiany w przestrzeni nazw są odzwierciedlane w słowniku, a zmiany w słowniku są odzwierciedlane w przestrzeni nazw:
class Test(object):
a = 'one'
b = 'two'
huh = locals()
c = 'three'
huh['d'] = 'four'
print huh
daje nam:
{
'a': 'one',
'b': 'two',
'c': 'three',
'd': 'four',
'huh': {...},
'__module__': '__main__',
}
Jak dotąd wszystko, o czym powiedziałem, locals()odnosi się również do vars()... oto różnica: vars()przyjmuje pojedynczy obiekt jako swój argument, a jeśli dasz mu obiekt, zwraca wartość __dict__tego obiektu. W przypadku typowego obiektu __dict__jest to miejsce, w którym przechowywana jest większość danych atrybutów. Obejmuje to zmienne klas i globalne modułów:
class Test(object):
a = 'one'
b = 'two'
def frobber(self):
print self.c
t = Test()
huh = vars(t)
huh['c'] = 'three'
t.frobber()
co daje nam:
three
Zauważ, że funkcja __dict__jest przestrzenią nazw atrybutu, a nie zmiennymi lokalnymi. __dict__Przechowywanie zmiennych lokalnych przez funkcję nie miałoby sensu , ponieważ rekurencja i wielowątkowość oznaczają, że w tym samym czasie może istnieć wiele wywołań funkcji, każde z własnymi lokalnymi:
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)
co daje nam:
Inner call locals: {'outer': False}
f.__dict__: {'x': 3}
Outer call locals: {'outer': True}
f.__dict__: {'x': 3}
Tutaj fwywołuje się rekurencyjnie, więc wewnętrzne i zewnętrzne wywołania nakładają się. Każdy z nich widzi swoje własne zmienne lokalne podczas wywołania locals(), ale oba wywołania widzą to samof.__dict__ i f.__dict__nie mają żadnych zmiennych lokalnych.
vars()lub locals()wywoływanego w funkcji eval(). EG: wyświetla def test(): huh = locals(); huh['d'] = 4; print eval('d')4 po test()wykonaniu!
dict(zwrócone przez locals()) jest odzwierciedlane w lokalnej przestrzeni nazw, a zmiany w lokalnej przestrzeni nazw są odzwierciedlane w dict(w moim Pythonie). Tyle tylko, że specyfikacja nie gwarantuje takiego zachowania.
import thisoraz w Googlesite:docs.python.org namespace