Что именно правила обзорных Python?
Если у меня есть код:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
Где находится x
? Некоторые возможные варианты включают список ниже:
- В прилагаемом исходном файле
- В пространстве имен класса
- В определении функции
- В индексной переменной цикла for
- Внутри для цикла
Также есть контекст во время выполнения, когда функция spam
передается куда-то еще. А может лямбда-функции проходят немного иначе?
Где-то должна быть простая ссылка или алгоритм. Это запутанный мир для программистов среднего уровня Python.
python
scope
dynamic-languages
Чарльз Мерриам
источник
источник
Ответы:
Собственно, краткое правило для разрешения Python Scope, из Learning Python, 3-е. Издание , (Эти правила относятся только к именам переменных, а не к атрибутам. Если вы ссылаетесь на них без точки, эти правила применяются.)
Правило LEGB
L ocal - Имена, назначенные любым способом внутри функции (
def
илиlambda
) и не объявленные глобальными в этой функцииE nclosing-function - Имена, назначенные в локальной области действия любой и всех статически включающих функций (
def
илиlambda
), от внутренней к внешней.G lobal (module) - Имена, назначенные на верхнем уровне файла модуля, или путем выполнения
global
оператора вdef
файлеB uilt в (Python) - Имена предустанавливаются в встроенном модуле имен:
open
,range
,SyntaxError
и т.д.Итак, в случае
for
Цикл не имеет свое собственное пространство имен. В порядке LEGB, области будутdef spam
(вcode3
,code4
иcode5
)def
)x
объявлены глобально в модуле (вcode1
)?x
в Python.x
никогда не будет найденоcode2
(даже в тех случаях, когда вы ожидаете, см . ответ Антти или здесь ).источник
global(var_name)
синтаксически неверен. Правильный синтаксис был быglobal var_name
без скобок. У вас есть правильное мнение, хотя.>>> def foo(x): ... y = x ... def bar(z): ... y = z ... bar(5) ... print x,y ... >>> foo(3) 3 3
y
пишется, аglobal y
объявлений нет - см. Комментарий Питера.По сути, единственное, что в Python представляет новую область видимости, - это определение функции. Классы - это особый случай, когда все, что определено непосредственно в теле, помещается в пространство имен класса, но они не доступны напрямую из методов (или вложенных классов), которые они содержат.
В вашем примере есть только 3 области, где x будет искать в:
область спама - содержащая все, что определено в code3 и code5 (а также code4, переменная вашего цикла)
Глобальная область - содержащая все, что определено в code1, а также Foo (и все, что меняется после него)
Встроенное пространство имен. Особый случай - он содержит различные встроенные функции и типы Python, такие как len () и str (). Как правило, это не должно быть изменено каким-либо пользовательским кодом, поэтому ожидайте, что он будет содержать стандартные функции и ничего больше.
Другие области видимости появляются только тогда, когда вы вводите вложенную функцию (или лямбду) в изображение. Однако они будут вести себя так, как и следовало ожидать. Вложенная функция может получить доступ ко всему в локальной области видимости, а также ко всему в области действия включающей функции. например.
Ограничения:
Переменные в областях, кроме переменных локальной функции, могут быть доступны, но не могут быть привязаны к новым параметрам без дополнительного синтаксиса. Вместо этого присваивание создаст новую локальную переменную вместо того, чтобы воздействовать на переменную в родительской области. Например:
Чтобы действительно изменить привязки глобальных переменных из области действия функции, необходимо указать, что переменная является глобальной с ключевым словом global. Например:
В настоящее время нет способа сделать то же самое для переменных во вложенных областях функций , но Python 3 вводит новое ключевое слово "
nonlocal
", которое будет действовать аналогично глобальному, но для областей вложенных функций.источник
Не было никакого подробного ответа относительно времени Python3, поэтому я сделал ответ здесь. Большая часть того, что здесь описано, подробно описана в разделе 4.2.2 Разрешение имен документации Python 3.
Как указано в других ответах, есть 4 основных области, LEGB, для Local, Enclosing, Global и Builtin. В дополнение к ним, существует специальная область видимости, тело класса , которая не содержит вмещающей области видимости для методов, определенных в классе; любые присваивания в теле класса делают переменную оттуда связанной в теле класса.
В частности, нет оператора блока, кроме как
def
иclass
, создать переменную область видимости. В Python 2 понимание списка не создает область видимости переменной, однако в Python 3 переменная цикла в пределах понимания списка создается в новой области видимости.Чтобы продемонстрировать особенности класса тела
Таким образом, в отличие от тела функции, вы можете переназначить переменную с тем же именем в теле класса, чтобы получить переменную класса с тем же именем; дальнейшие поиски по этому имени вместо этого преобразуются в переменную класса.
Один из самых больших сюрпризов для многих новичков в Python - это то, что
for
цикл не создает переменную область видимости. В Python 2 понимание списка также не создает область действия (в то время как генераторы и вычисления dict делают это!) Вместо этого они пропускают значение в функции или глобальной области видимости:Понимания могут быть использованы как хитрый (или ужасный, если хотите) способ создания изменяемых переменных в лямбда-выражениях в Python 2 - лямбда-выражение создает переменную область видимости, как это делает
def
оператор, но внутри лямбды операторы не допускаются. Назначение, являющееся оператором в Python, означает, что никакие переменные назначения в лямбде не допускаются, но понимание списка - это выражение ...Это поведение было исправлено в Python 3 - нет выражений понимания или генераторов утечек переменных.
Глобальный действительно означает область видимости модуля; основной модуль Python является
__main__
; все импортированные модули доступны черезsys.modules
переменную; чтобы получить доступ к__main__
одному можно использоватьsys.modules['__main__']
, илиimport __main__
; это вполне приемлемо для доступа и назначения атрибутов там; они будут отображаться как переменные в глобальной области видимости основного модуля.Если имя когда-либо назначено в текущей области (за исключением области класса), оно будет считаться принадлежащим этой области, в противном случае оно будет считаться принадлежащим какой-либо вмещающей области, которая присваивается переменной (оно может быть не назначено). пока или нет) или, наконец, глобальный охват. Если переменная считается локальной, но она еще не установлена или была удалена, результатом будет чтение значения переменной
UnboundLocalError
, которое является подклассомNameError
.Область действия может объявить, что она явно хочет изменить глобальную переменную (область действия модуля) с помощью ключевого слова global:
Это также возможно, даже если оно было затенено в прилагаемой области видимости:
В Python 2 нет простого способа изменить значение в рамках объема; обычно это моделируется изменяемым значением, таким как список с длиной 1:
Однако в Python 3
nonlocal
приходит на помощь:В
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 с помощью:На
from __future__ import print_function
самом делеprint
функция не импортирует функцию в Python 2 - вместо этого она просто отключает правила синтаксического анализа дляprint
оператора в текущем модуле, обрабатывает,print
как и любой другой идентификатор переменной, и, таким образом, позволяетprint
искать функцию во встроенных программах.источник
Правила области видимости для Python 2.x были изложены уже в других ответах. Единственное, что я хотел бы добавить, - это то, что в Python 3.0 также существует концепция нелокальной области (обозначается ключевым словом «nonlocal»). Это позволяет вам получить прямой доступ к внешним областям и открывает возможность делать некоторые хитрые трюки, в том числе лексические замыкания (без уродливых хаков, связанных с изменяемыми объектами).
РЕДАКТИРОВАТЬ: Вот PEP с дополнительной информацией об этом.
источник
Немного более полный пример объема:
вывод:
источник
method
иmethod_local_ref
должны быть выделены.method
может получить доступ к глобальной переменной и распечатать ее как в5. Global x
. Ноmethod_local_ref
не может, потому что позже он определяет локальную переменную с тем же именем. Вы можете проверить это, убравx = 200
строку и увидев разницуPython разрешает ваши переменные с - обычно - тремя доступными пространствами имен.
Есть две функции:
globals
иlocals
которые показывают вам содержимое этих двух пространств имен.Пространства имен создаются пакетами, модулями, классами, конструкциями объектов и функциями. Других видов пространств имен нет.
В этом случае вызов названной функции
x
должен быть разрешен в локальном пространстве имен или глобальном пространстве имен.Локальным в этом случае является тело функции метода
Foo.spam
.Глобальный - хорошо - глобальный.
Правило заключается в поиске во вложенных локальных пространствах, созданных функциями метода (и определениях вложенных функций), а затем в глобальном поиске. Вот и все.
Других возможностей нет.
for
Заявление (и другие составные высказывания , какif
иtry
) не создавать новую вложенную область видимости. Только определения (пакеты, модули, функции, классы и экземпляры объектов.)Внутри определения класса имена являются частью пространства имен класса.
code2
Например, должен быть квалифицирован по имени класса. ВообщеFoo.code2
. Тем не менее,self.code2
это также будет работать, потому что объекты Python смотрят на содержащий класс как запасной вариант.Объект (экземпляр класса) имеет переменные экземпляра. Эти имена находятся в пространстве имен объекта. Они должны быть квалифицированы по объекту. (
variable.instance
.)Из метода класса у вас есть локальные и глобальные переменные. Вы говорите,
self.variable
чтобы выбрать экземпляр в качестве пространства имен. Вы заметите, чтоself
это аргумент каждой функции-члена класса, делающий ее частью локального пространства имен.См Python Scope правила , Python Область , Область видимости переменной .
источник
Python has two namespaces available. Global and local-to-something.
х не найден, так как вы его не определили. :-) Его можно найти в code1 (глобальный) или code3 (локальный), если вы поместите его туда.
code2 (члены класса) не видны для кода внутри методов того же класса - вы обычно получаете к ним доступ, используя self. code4 / code5 (циклы) находятся в той же области видимости, что и code3, поэтому, если вы записали туда x, вы бы изменили экземпляр x, определенный в code3, а не создавали новый x.
Python статически ограничен, поэтому, если вы передадите «spam» другой функции, spam по-прежнему будет иметь доступ к глобальным переменным в модуле, из которого он получен (определен в code1), и любым другим содержащим области (см. Ниже). Члены code2 снова будут доступны через себя.
лямбда не отличается от def. Если в функции используется лямбда-выражение, это то же самое, что и определение вложенной функции. Начиная с версии Python 2.2 доступны вложенные области видимости. В этом случае вы можете связать x на любом уровне вложенности функций, и Python подберет самый внутренний экземпляр:
fun3 видит экземпляр x из ближайшей содержащей области, которая является областью функции, связанной с fun2. Но другие x-экземпляры, определенные в fun1 и глобально, не затрагиваются.
До nested_scopes - в Python pre-2.1 и в 2.1, если только вы специально не запрашиваете функцию, использующую импорт из будущего - области действия fun1 и fun2 не видны для fun3, поэтому ответ S.Lott верен, и вы получите глобальный x :
источник
В Python
Если переменная не может быть найдена в текущей области, пожалуйста, обратитесь к порядку LEGB.
источник