Python Language
Zmienny zakres i wiązanie
Szukaj…
Składnia
- globalne a, b, c
- nielokalne a, b
- x = coś # wiąże x
- (x, y) = coś # wiąże xiy
- x + = coś # wiąże x. Podobnie dla wszystkich innych „op =”
- del x # wiąże x
- dla x w czymś: # wiąże x
- z czymś, co x: # wiąże x
- oprócz Wyjątku jako ex: # wiąże ex wewnątrz bloku
Zmienne globalne
W Pythonie zmienne wewnątrz funkcji są uważane za lokalne wtedy i tylko wtedy, gdy pojawiają się po lewej stronie instrukcji przypisania lub w innym powiązaniu; w przeciwnym razie takie powiązanie jest sprawdzane w ramach funkcji obejmujących zakres globalny. Dzieje się tak nawet wtedy, gdy instrukcja przypisania nigdy nie jest wykonywana.
x = 'Hi'
def read_x():
print(x) # x is just referenced, therefore assumed global
read_x() # prints Hi
def read_y():
print(y) # here y is just referenced, therefore assumed global
read_y() # NameError: global name 'y' is not defined
def read_y():
y = 'Hey' # y appears in an assignment, therefore it's local
print(y) # will find the local y
read_y() # prints Hey
def read_x_local_fail():
if False:
x = 'Hey' # x appears in an assignment, therefore it's local
print(x) # will look for the _local_ z, which is not assigned, and will not be found
read_x_local_fail() # UnboundLocalError: local variable 'x' referenced before assignment
Zwykle przypisanie w zakresie przesłania wszelkie zewnętrzne zmienne o tej samej nazwie:
x = 'Hi'
def change_local_x():
x = 'Bye'
print(x)
change_local_x() # prints Bye
print(x) # prints Hi
Deklaracja nazwy global
oznacza, że dla pozostałej części zakresu wszelkie przypisania do nazwy będą miały miejsce na najwyższym poziomie modułu:
x = 'Hi'
def change_global_x():
global x
x = 'Bye'
print(x)
change_global_x() # prints Bye
print(x) # prints Bye
global
słowo kluczowe oznacza, że przypisania będą się odbywały na najwyższym poziomie modułu, a nie na najwyższym poziomie programu. Inne moduły nadal będą wymagały zwykłego dostępu kropkowego do zmiennych w module.
Podsumowując: aby wiedzieć, czy zmienna x
jest lokalna dla funkcji, powinieneś przeczytać całą funkcję:
- jeśli znalazłeś
global x
, tox
jest zmienną globalną - Jeśli znalazłeś
nonlocal x
,x
należy do funkcji zamykającej i nie jest ani lokalny, ani globalny - Jeśli znalazłeś
x = 5
lubfor x in range(3)
lub jakieś inne wiązanie, tox
jest zmienną lokalną - W przeciwnym razie
x
należy do zakresu obejmującego (zakres funkcji, zasięg globalny lub wbudowane)
Zmienne lokalne
Jeśli nazwa jest związana wewnątrz funkcji, domyślnie jest dostępna tylko w obrębie funkcji:
def foo():
a = 5
print(a) # ok
print(a) # NameError: name 'a' is not defined
Konstrukty przepływ sterowania nie mają wpływu na zakres (z wyjątkiem except
), ale dostęp do zmiennej, która nie została jeszcze przypisana jest błąd:
def foo():
if True:
a = 5
print(a) # ok
b = 3
def bar():
if False:
b = 5
print(b) # UnboundLocalError: local variable 'b' referenced before assignment
Typowymi operacjami wiązania są przypisania for
pętli i rozszerzone przypisania, takie jak a += 5
Zmienne nielokalne
Python 3 dodał nowe słowo kluczowe o nazwie nielokalne . Nielokalne słowo kluczowe dodaje przesłonięcie zakresu do zakresu wewnętrznego. Możesz przeczytać o tym wszystko w PEP 3104 . Najlepiej ilustruje to kilka przykładów kodu. Jednym z najczęstszych przykładów jest utworzenie funkcji, która może zwiększać:
def counter():
num = 0
def incrementer():
num += 1
return num
return incrementer
Jeśli spróbujesz uruchomić ten kod, otrzymasz UnboundLocalError, ponieważ zmienna num jest wywoływana przed przypisaniem jej w najbardziej wewnętrznej funkcji. Dodajmy nielokalne do miksu:
def counter():
num = 0
def incrementer():
nonlocal num
num += 1
return num
return incrementer
c = counter()
c() # = 1
c() # = 2
c() # = 3
Zasadniczo nonlocal
pozwolą ci przypisywać zmienne w zakresie zewnętrznym, ale nie w zakresie globalnym. Więc nie możesz użyć nonlocal
w naszej funkcji counter
ponieważ wówczas próbowałaby ona przypisać do zasięgu globalnego. Spróbuj, a szybko otrzymasz błąd SyntaxError
. Zamiast tego należy użyć funkcji nonlocal
w funkcji zagnieżdżonej.
(Należy zauważyć, że funkcja przedstawiona tutaj jest lepiej zaimplementowana za pomocą generatorów).
Wiążące wystąpienie
x = 5
x += 7
for x in iterable: pass
Każda z powyższych instrukcji jest zjawiskiem wiążącym - x
wiąże się z obiektem oznaczonym przez 5
. Jeśli to polecenie pojawi się wewnątrz funkcji, to x
będzie domyślnie lokalne dla funkcji. Zobacz sekcję „Składnia”, aby uzyskać listę wiążących instrukcji.
Funkcje pomijają zakres klas podczas wyszukiwania nazw
Klasy mają zasięg lokalny podczas definicji, ale funkcje wewnątrz klasy nie używają tego zasięgu podczas wyszukiwania nazw. Ponieważ lambdy są funkcjami, a wyrażenia są implementowane przy użyciu zakresu funkcji, może to prowadzić do zaskakujących zachowań.
a = 'global'
class Fred:
a = 'class' # class scope
b = (a for i in range(10)) # function scope
c = [a for i in range(10)] # function scope
d = a # class scope
e = lambda: a # function scope
f = lambda a=a: a # default argument uses class scope
@staticmethod # or @classmethod, or regular instance method
def g(): # function scope
return a
print(Fred.a) # class
print(next(Fred.b)) # global
print(Fred.c[0]) # class in Python 2, global in Python 3
print(Fred.d) # class
print(Fred.e()) # global
print(Fred.f()) # class
print(Fred.g()) # global
Użytkownicy niezaznajomieni z działaniem tego zakresu mogą spodziewać się, że b
, c
i e
wydrukują class
.
Od PEP 227 :
Nazwy w zakresie klas nie są dostępne. Nazwy są rozwiązywane w najbardziej wewnętrznym obejmującym zakresie funkcji. Jeśli definicja klasy występuje w łańcuchu zasięgów zagnieżdżonych, proces rozwiązywania pomija definicje klas.
Z dokumentacji Pythona na temat nazewnictwa i wiązania :
Zakres nazw zdefiniowanych w bloku klasy jest ograniczony do bloku klasy; nie obejmuje bloków metod - obejmuje to wyrażenia i wyrażenia generatora, ponieważ są one implementowane przy użyciu zakresu funkcji. Oznacza to, że następujące działania nie powiodą się:
class A: a = 42 b = list(a + i for i in range(10))
W tym przykładzie wykorzystano odniesienia do tej odpowiedzi autorstwa Martijna Pietersa, który zawiera bardziej dogłębną analizę tego zachowania.
Polecenie del
To polecenie ma kilka powiązanych, ale odrębnych form.
del v
Jeśli v
jest zmienną, polecenie del v
usuwa zmienną ze swojego zakresu. Na przykład:
x = 5
print(x) # out: 5
del x
print(x) # NameError: name 'f' is not defined
Zauważ, że
del
jest zjawiskiem wiążącym , co oznacza, że o ile wyraźnie nie zaznaczono inaczej (użycienonlocal
lubglobal
),del v
spowoduje, żev
będzie lokalny dla bieżącego zakresu. Jeśli zamierzasz usunąćv
w zakresie zewnętrznym, użyjnonlocal v
lubglobal v
w tym samym zakresie instrukcjidel v
.
We wszystkich poniższych przypadkach zamiar polecenia jest zachowaniem domyślnym, ale nie jest wymuszony przez język. Klasa może być napisana w sposób, który unieważnia ten zamiar.
del v.name
To polecenie wyzwala połączenie z v.__delattr__(name)
.
Chodzi o to, aby name
atrybutu była niedostępna. Na przykład:
class A:
pass
a = A()
a.x = 7
print(a.x) # out: 7
del a.x
print(a.x) # error: AttributeError: 'A' object has no attribute 'x'
del v[item]
To polecenie wyzwala wywołanie do v.__delitem__(item)
.
Intencją jest, aby item
nie należał do odwzorowania zaimplementowanego przez obiekt v
. Na przykład:
x = {'a': 1, 'b': 2}
del x['a']
print(x) # out: {'b': 2}
print(x['a']) # error: KeyError: 'a'
del v[a:b]
To faktycznie wywołuje v.__delslice__(a, b)
.
Intencja jest podobna do opisanej powyżej, ale z plasterkami - zakresami przedmiotów zamiast jednego przedmiotu. Na przykład:
x = [0, 1, 2, 3, 4]
del x[1:3]
print(x) # out: [0, 3, 4]
Zobacz także Garbage Collection # Polecenie del .
Zakres lokalny a globalny
Jaki jest zasięg lokalny i globalny?
Wszystkie zmienne Pythona, które są dostępne w pewnym momencie kodu, mają zasięg lokalny lub globalny .
Wyjaśnienie jest takie, że zasięg lokalny obejmuje wszystkie zmienne zdefiniowane w bieżącej funkcji, a zasięg globalny obejmuje zmienne zdefiniowane poza bieżącą funkcją.
foo = 1 # global
def func():
bar = 2 # local
print(foo) # prints variable foo from global scope
print(bar) # prints variable bar from local scope
Można sprawdzić, które zmienne są w jakim zakresie. Wbudowane funkcje locals()
i globals()
zwracają całe zakresy jako słowniki.
foo = 1
def func():
bar = 2
print(globals().keys()) # prints all variable names in global scope
print(locals().keys()) # prints all variable names in local scope
Co dzieje się z konfliktami nazw?
foo = 1
def func():
foo = 2 # creates a new variable foo in local scope, global foo is not affected
print(foo) # prints 2
# global variable foo still exists, unchanged:
print(globals()['foo']) # prints 1
print(locals()['foo']) # prints 2
Aby zmodyfikować zmienną globalną, użyj słowa kluczowego global
:
foo = 1
def func():
global foo
foo = 2 # this modifies the global foo, rather than creating a local variable
Zakres jest zdefiniowany dla całego ciała funkcji!
Oznacza to, że zmienna nigdy nie będzie globalna przez połowę funkcji, a później lokalnie, lub odwrotnie.
foo = 1
def func():
# This function has a local variable foo, because it is defined down below.
# So, foo is local from this point. Global foo is hidden.
print(foo) # raises UnboundLocalError, because local foo is not yet initialized
foo = 7
print(foo)
Podobnie przeciwieństwo:
foo = 1
def func():
# In this function, foo is a global variable from the begining
foo = 7 # global foo is modified
print(foo) # 7
print(globals()['foo']) # 7
global foo # this could be anywhere within the function
print(foo) # 7
Funkcje w ramach funkcji
Może istnieć wiele poziomów funkcji zagnieżdżonych w obrębie funkcji, ale w obrębie każdej funkcji istnieje tylko jeden zasięg lokalny dla tej funkcji i zakres globalny. Brak pośrednich zakresów.
foo = 1
def f1():
bar = 1
def f2():
baz = 2
# here, foo is a global variable, baz is a local variable
# bar is not in either scope
print(locals().keys()) # ['baz']
print('bar' in locals()) # False
print('bar' in globals()) # False
def f3():
baz = 3
print(bar) # bar from f1 is referenced so it enters local scope of f3 (closure)
print(locals().keys()) # ['bar', 'baz']
print('bar' in locals()) # True
print('bar' in globals()) # False
def f4():
bar = 4 # a new local bar which hides bar from local scope of f1
baz = 4
print(bar)
print(locals().keys()) # ['bar', 'baz']
print('bar' in locals()) # True
print('bar' in globals()) # False
global
vs nonlocal
(tylko Python 3)
Oba te słowa kluczowe są używane do uzyskania dostępu do zapisu do zmiennych, które nie są lokalne dla bieżących funkcji.
global
słowo kluczowe deklaruje, że nazwę należy traktować jako zmienną globalną.
foo = 0 # global foo
def f1():
foo = 1 # a new foo local in f1
def f2():
foo = 2 # a new foo local in f2
def f3():
foo = 3 # a new foo local in f3
print(foo) # 3
foo = 30 # modifies local foo in f3 only
def f4():
global foo
print(foo) # 0
foo = 100 # modifies global foo
Z drugiej strony, nonlocal
(patrz Zmienne nonlocal
), dostępne w Pythonie 3, przejmuje zmienną lokalną z zakresu obejmującego do zakresu lokalnego bieżącej funkcji.
Z dokumentacji Pythona na temat nonlocal
:
Instrukcja nielokalna powoduje, że wymienione identyfikatory odnoszą się do poprzednio powiązanych zmiennych w najbliższym obejmującym zakresie z wyłączeniem globali.
def f1():
def f2():
foo = 2 # a new foo local in f2
def f3():
nonlocal foo # foo from f2, which is the nearest enclosing scope
print(foo) # 2
foo = 20 # modifies foo from f2!