Python Language
Область переменных и привязка
Поиск…
Синтаксис
- глобальные a, b, c
- нелокальный a, b
- x = что-то # связывает x
- (x, y) = что-то # связывает x и y
- x + = что-то # связывает x. Аналогично для всех остальных "op ="
- del x # binds x
- для x в чем-то: # binds x
- с чем-то как x: # binds x
- кроме Exception как ex: # связывает ex внутренний блок
Глобальные переменные
В Python переменные внутри функций считаются локальными тогда и только тогда, когда они появляются в левой части оператора присваивания или в каком-либо другом случае привязки; в противном случае такая привязка просматривается в приложениях, вплоть до глобальной области. Это верно, даже если оператор присваивания никогда не выполняется.
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
Обычно присваивание внутри области видимости будет теневой для любых внешних переменных с тем же именем:
x = 'Hi'
def change_local_x():
x = 'Bye'
print(x)
change_local_x() # prints Bye
print(x) # prints Hi
Объявление global
имени означает, что для остальной части области все назначения имени будут выполняться на верхнем уровне модуля:
x = 'Hi'
def change_global_x():
global x
x = 'Bye'
print(x)
change_global_x() # prints Bye
print(x) # prints Bye
global
ключевое слово означает, что назначения будут выполняться на верхнем уровне модуля, а не на верхнем уровне программы. Другие модули по-прежнему нуждаются в обычном пунктирном доступе к переменным в модуле.
Подводя итог: чтобы узнать, является ли переменная x
локальной для функции, вы должны прочитать всю функцию:
- если вы нашли
global x
, тоx
является глобальной переменной - Если вы нашли
nonlocal x
, тоx
принадлежит закрывающей функции и не является ни локальной, ни глобальной - Если вы нашли
x = 5
илиfor x in range(3)
или какой-либо другой привязке, тоx
является локальной переменной - В противном случае
x
относится к некоторой охватывающей области (область действия, глобальная область или встроенные функции)
Локальные переменные
Если имя связано внутри функции, оно по умолчанию доступно только внутри функции:
def foo():
a = 5
print(a) # ok
print(a) # NameError: name 'a' is not defined
Конструкции потока управления не влияют на область действия (за исключением except
), но доступ к переменной, которая еще не была назначена, является ошибкой:
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
Обычными операциями связывания являются назначения, for
циклов и расширенные назначения, такие как a += 5
Нелокальные переменные
Python 3 добавил новое ключевое слово, называемое нелокальным . Нелокальное ключевое слово добавляет переопределение области к внутренней области. Вы можете прочитать все об этом в PEP 3104 . Это лучше всего иллюстрируется несколькими примерами кода. Одним из наиболее распространенных примеров является создание функции, которая может увеличиваться:
def counter():
num = 0
def incrementer():
num += 1
return num
return incrementer
Если вы попытаетесь запустить этот код, вы получите UnboundLocalError, потому что переменная num ссылается прежде, чем она будет назначена в самой внутренней функции. Давайте добавим нелокальное в микс:
def counter():
num = 0
def incrementer():
nonlocal num
num += 1
return num
return incrementer
c = counter()
c() # = 1
c() # = 2
c() # = 3
В основном nonlocal
позволяет вам назначать переменные во внешней области, но не глобальную область. Таким образом, вы не можете использовать nonlocal
в нашей функции counter
потому что тогда он попытается присвоить глобальную область. Попробуйте, и вы быстро получите SyntaxError
. Вместо этого вы должны использовать nonlocal
во вложенной функции.
(Обратите внимание, что функциональность, представленная здесь, лучше реализована с использованием генераторов.)
Привязка
x = 5
x += 7
for x in iterable: pass
Каждое из вышеуказанных утверждений является вложением привязки - x
становится привязанным к объекту, обозначенному символом 5
. Если это утверждение появляется внутри функции, то x
будет функция локального по умолчанию. См. Раздел «Синтаксис» для списка операторов привязки.
Функции пропускают область класса при поиске имен
Классы имеют локальную область видимости во время определения, но функции внутри класса не используют эту область при поиске имен. Поскольку lambdas - это функции, а понимание реализуется с использованием области функций, это может привести к неожиданному поведению.
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
Пользователи, незнакомые с тем, как работает эта область действия, могут ожидать b
, c
и e
для печати class
.
От PEP 227 :
Имена в классе не доступны. Имена разрешаются в самой внутренней области приложения. Если определение класса происходит в цепочке вложенных областей, процесс разрешения пропускает определения классов.
Из документации Python по именованию и привязке :
Объем имен, определенных в блоке класса, ограничен блоком класса; он не распространяется на кодовые блоки методов - это включает в себя выражения и выражения генератора, поскольку они реализованы с использованием области функций. Это означает, что следующее:
class A: a = 42 b = list(a + i for i in range(10))
В этом примере используются ссылки из этого ответа Martijn Pieters, в котором содержится более подробный анализ этого поведения.
Команда del
Эта команда имеет несколько взаимосвязанных, но разных форм.
del v
Если v
- переменная, команда del v
удаляет переменную из ее области. Например:
x = 5
print(x) # out: 5
del x
print(x) # NameError: name 'f' is not defined
Обратите внимание, что
del
- это событие привязки , а это означает, что если явно не указано иначе (используяnonlocal
илиglobal
),del v
сделаетv
локальным в текущей области. Если вы хотите удалитьv
во внешней области, используйтеnonlocal v
илиglobal v
в той же области действия инструкцииdel v
.
Во всем следующем, намерение команды является поведением по умолчанию, но не выполняется на языке. Класс может быть написан таким образом, что это недействительно.
del v.name
Эта команда вызывает вызов v.__delattr__(name)
.
Цель состоит в том, чтобы сделать name
атрибута недоступным. Например:
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]
Эта команда вызывает вызов v.__delitem__(item)
.
Цель состоит в том, что item
не будет принадлежать отображению, реализуемому объектом v
. Например:
x = {'a': 1, 'b': 2}
del x['a']
print(x) # out: {'b': 2}
print(x['a']) # error: KeyError: 'a'
del v[a:b]
Это фактически вызывает v.__delslice__(a, b)
.
Цель аналогична описанной выше, но с фрагментами - диапазонами элементов вместо одного элемента. Например:
x = [0, 1, 2, 3, 4]
del x[1:3]
print(x) # out: [0, 3, 4]
См. Также Сбор мусора # Команда del .
Локальная и глобальная область
Каковы местные и глобальные масштабы?
Все переменные Python, доступные в некоторой точке кода, находятся либо в локальной области, либо в глобальной области .
Объяснение заключается в том, что локальная область включает все переменные, определенные в текущей функции, а глобальная область включает переменные, определенные за пределами текущей функции.
foo = 1 # global
def func():
bar = 2 # local
print(foo) # prints variable foo from global scope
print(bar) # prints variable bar from local scope
Можно проверить, какие переменные находятся в этой области. Встроенные функции locals()
и globals()
возвращают целые области в качестве словарей.
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
Что происходит с именами?
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
Чтобы изменить глобальную переменную, используйте ключевое слово global
:
foo = 1
def func():
global foo
foo = 2 # this modifies the global foo, rather than creating a local variable
Объем определяется для всего тела функции!
Это означает, что переменная никогда не будет глобальной для половины функции, а затем локальной или наоборот.
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)
Аналогичным образом, oposite:
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
Функции внутри функций
Внутри функций может быть много уровней функций, но внутри любой одной функции есть только одна локальная область для этой функции и глобальной области. Нет промежуточных областей.
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
или nonlocal
(только для Python 3)
Оба этих ключевых слова используются для получения доступа на запись к переменным, которые не являются локальными для текущих функций.
global
ключевое слово объявляет, что имя должно рассматриваться как глобальная переменная.
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
С другой стороны, nonlocal
(см. Nonlocal Variables ), доступные в Python 3, берут локальную переменную из охватывающей области в локальную область текущей функции.
Из документации Python по nonlocal
:
Нелокальный оператор заставляет перечисленные идентификаторы ссылаться на ранее связанные переменные в ближайшей охватывающей области, исключая глобальные переменные.
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!