Не было никакого подробного ответа относительно времени Python3, поэтому я сделал ответ здесь. Большая часть того, что здесь описано, подробно описана в разделе 4.2.2 Разрешение имен документации Python 3.
Как указано в других ответах, есть 4 основных области, LEGB, для Local, Enclosing, Global и Builtin. В дополнение к ним, существует специальная область видимости, тело класса , которая не содержит вмещающей области видимости для методов, определенных в классе; любые присваивания в теле класса делают переменную оттуда связанной в теле класса.
В частности, нет оператора блока, кроме как def
и class
, создать переменную область видимости. В Python 2 понимание списка не создает область видимости переменной, однако в Python 3 переменная цикла в пределах понимания списка создается в новой области видимости.
Чтобы продемонстрировать особенности класса тела
x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
Таким образом, в отличие от тела функции, вы можете переназначить переменную с тем же именем в теле класса, чтобы получить переменную класса с тем же именем; дальнейшие поиски по этому имени вместо этого преобразуются в переменную класса.
Один из самых больших сюрпризов для многих новичков в Python - это то, что for
цикл не создает переменную область видимости. В Python 2 понимание списка также не создает область действия (в то время как генераторы и вычисления dict делают это!) Вместо этого они пропускают значение в функции или глобальной области видимости:
>>> [ i for i in range(5) ]
>>> i
4
Понимания могут быть использованы как хитрый (или ужасный, если хотите) способ создания изменяемых переменных в лямбда-выражениях в Python 2 - лямбда-выражение создает переменную область видимости, как это делает def
оператор, но внутри лямбды операторы не допускаются. Назначение, являющееся оператором в Python, означает, что никакие переменные назначения в лямбде не допускаются, но понимание списка - это выражение ...
Это поведение было исправлено в Python 3 - нет выражений понимания или генераторов утечек переменных.
Глобальный действительно означает область видимости модуля; основной модуль Python является __main__
; все импортированные модули доступны через sys.modules
переменную; чтобы получить доступ к __main__
одному можно использовать sys.modules['__main__']
, или import __main__
; это вполне приемлемо для доступа и назначения атрибутов там; они будут отображаться как переменные в глобальной области видимости основного модуля.
Если имя когда-либо назначено в текущей области (за исключением области класса), оно будет считаться принадлежащим этой области, в противном случае оно будет считаться принадлежащим какой-либо вмещающей области, которая присваивается переменной (оно может быть не назначено). пока или нет) или, наконец, глобальный охват. Если переменная считается локальной, но она еще не установлена или была удалена, результатом будет чтение значения переменной UnboundLocalError
, которое является подклассом NameError
.
x = 5
def foobar():
print(x) # causes UnboundLocalError!
x += 1 # because assignment here makes x a local variable within the function
# call the function
foobar()
Область действия может объявить, что она явно хочет изменить глобальную переменную (область действия модуля) с помощью ключевого слова global:
x = 5
def foobar():
global x
print(x)
x += 1
foobar() # -> 5
print(x) # -> 6
Это также возможно, даже если оно было затенено в прилагаемой области видимости:
x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> 5 911
print(x, y) # -> 6 13
В Python 2 нет простого способа изменить значение в рамках объема; обычно это моделируется изменяемым значением, таким как список с длиной 1:
def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
Однако в Python 3 nonlocal
приходит на помощь:
def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
В nonlocal
документации сказано, что
Имена, перечисленные в нелокальном операторе, в отличие от имен, перечисленных в глобальном операторе, должны ссылаться на ранее существовавшие привязки во вложенной области (область, в которой должна быть создана новая привязка, не может быть определена однозначно).
т. е. nonlocal
всегда относится к самой внутренней внешней неглобальной области, где имя было связано (т. е. присвоено, в том числе используется в качестве for
целевой переменной, в with
предложении или в качестве параметра функции).
Любая переменная, которая не считается локальной для текущей области или любой включающей области, является глобальной переменной. Глобальное имя ищется в глобальном словаре модуля; если он не найден, глобальный объект ищется из встроенного модуля; название модуля было изменено с python 2 на python 3; в Python 2 это было __builtin__
и в Python 3 теперь называется builtins
. Если вы назначите атрибут встроенного модуля, он будет виден после этого любому модулю как читаемая глобальная переменная, если только этот модуль не затеняет их своей глобальной переменной с тем же именем.
Чтение встроенного модуля также может быть полезным; Предположим, что вам нужна функция печати в стиле Python 3 в некоторых частях файла, но в других частях файла все еще используется print
оператор. В Python 2.6-2.7 вы можете получить print
функцию Python 3 с помощью:
import __builtin__
print3 = __builtin__.__dict__['print']
На from __future__ import print_function
самом деле print
функция не импортирует функцию в Python 2 - вместо этого она просто отключает правила синтаксического анализа для print
оператора в текущем модуле, обрабатывает, print
как и любой другой идентификатор переменной, и, таким образом, позволяет print
искать функцию во встроенных программах.