2008-11-15 3 views
346

Что такое точно - это правила обзора Python?Краткое описание правил оглавления?

Если у меня есть некоторый код:

code1 
class Foo: 
    code2 
    def spam..... 
     code3 
     for code4..: 
     code5 
     x() 

Где х найдено? Некоторые возможные варианты включают в себя выше список:

  1. В исходном вшита файл
  2. В пространстве имен класса
  3. В определении функции
  4. В для индекса петли переменной
  5. внутри для цикла

Также существует контекст во время выполнения, когда спам функции передается где-то в другом месте. И, может быть, функции лямбда проходят немного по-другому?

Должна быть простая ссылка или алгоритм где-то. Это запутанный мир для промежуточных программистов Python.

+2

люди могли прекратить делать небольшие "кармы изменения" на этот вопрос, пожалуйста? – 2017-03-24 19:53:10

+2

Они не все «редактирование кармы». Некоторые из них потому, что люди не понимают, как все работает. См. [** _ Если вопросы включают «теги» в их названиях? _ **] (https://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles). – martineau 2017-04-23 03:10:13

ответ

313

на самом деле, краткое правило для разрешения Scope Python, из Learning Python, 3rd. Ed.. (Эти правила относятся только к именам переменных, а не к атрибутам. Если вы ссылаетесь на него без какого-либо периода, применяются эти правила)

LEGB Rule.

L, местные - имена, назначенные какой-либо образом в функции (def или lambda)), а не объявлены глобальными в этой функции.

Е, вшита-функция местные жители - имя в локальной области любой и все статически ограждающие функции (def или lambda), от внутреннего к внешнему.

G, Global (модуль) - Имена, назначенные на верхнем уровне файла модуля, или путем выполнения global заявления в def в файл.

B, встроенный (Python) - Имена наперед заданного в встроенный модуль имен: open, range, SyntaxError, ...

Таким образом, в случае

code1 
class Foo: 
    code2 
    def spam..... 
     code3 
     for code4..: 
     code5 
     x() 

Цикл for не имеет собственного пространства имен. В LEGB порядке, прицелы бы

л: локальная, в def spamcode3, code 4, code5).

Е: закрываемые функции, любые ограждающие функции (если весь пример был в другом def)

G: глобальный. Были ли в модуле объявлены x (code1)?

B: Любой встроенный x в Python.

x никогда не будут найдены в code2 (даже в тех случаях, когда можно было бы ожидать, что будет, см Antti's answer или here).

8

Python решает свои переменные с - в общем случае - тремя пространствами имен.

В любой момент во время выполнения, есть по крайней мере три вложенных области видимости, чья пространств имен непосредственно доступны: самые внутренний размах, который искал во-первых, содержит локальные имена; пространства имен любых закрывающих функций, , поиск которых начинается с ближайшей охватывающей области; средняя область , поиск в следующем списке, содержит глобальные имена текущего модуля ; и внешняя область (поиск последней) - это пространство имен , содержащее встроенные имена.

Есть две функции: globals и locals, которые показывают вам содержание двух из этих пространств имен.

Пространства имен создаются пакетами, модулями, классами, конструкцией объектов и функциями. Других ароматов пространств имен нет.

В этом случае вызов функции с именем x должен быть разрешен в локальном пространстве имен или в глобальном пространстве имен.

Местный в этом случае является телом функции метода Foo.spam.

Глобальный - хорошо - глобальный.

Правило состоит в том, чтобы искать вложенные локальные пространства, созданные функциями метода (и определениями вложенных функций), а затем искать глобальные. Вот и все.

Нет других областей применения. Оператор for (и другие составные операторы, такие как if и try) не создают новые вложенные области. Только определения (пакеты, модули, функции, классы и экземпляры объектов.)

Внутри определения класса имена являются частью пространства имен классов. code2, например, должно быть квалифицировано именем класса. Обычно Foo.code2. Тем не менее, self.code2 также будет работать, потому что объекты Python смотрят на содержащийся класс в качестве спада.

Объект (экземпляр класса) имеет переменные экземпляра. Эти имена находятся в пространстве имен объекта. Они должны быть квалифицированы объектом. (variable.instance.)

Внутри метода класса у вас есть местные и глобальные. Вы говорите self.variable, чтобы выбрать экземпляр как пространство имен. Вы заметите, что self является аргументом для каждой функции-члена класса, что делает его частью локального пространства имен.

См. Python Scope Rules, Python Scope, Variable Scope.

+4

Это устаревшее. Начиная с версии 2.1 (7 лет назад) существует более двух областей, так как вложенные функции вводят новые области видимости, поэтому функция внутри функции будет иметь доступ к ее локальной области видимости, охватывающей области функций и глобальной области (также встроенным). – Brian 2008-11-15 21:24:00

+0

Прошу прощения, это уже не так. `Python имеет два пространства имен. Global и local-to-something.` – 2008-11-16 00:56:26

5

Где найти?

x не найден, так как вы не определили его. :-) Это можно найти в code1 (global) или code3 (local), если вы поместите его там.

code2 (члены класса) не видны для кода внутри методов одного и того же класса - вы обычно обращались к ним с помощью self. code4/code5 (петли) живут в том же объеме, что и код3, поэтому, если вы написали x в этом месте, вы бы изменили экземпляр x, определенный в коде3, не создавая новый x.

Python имеет статическую область, поэтому, если вы передаете спам на другую функцию, спам по-прежнему будет иметь доступ к глобалам в модуле, из которого он пришел (определен в коде1), и в любых других областях (см. Ниже). члены code2 будут снова доступны через self.

lambda ничем не отличается от def. Если у вас есть лямбда, используемая внутри функции, это то же самое, что и определение вложенной функции. В Python 2.2 и далее доступны вложенные области. В этом случае вы можете связать й на любом уровне вложенности функции и Python подберет сокровенную экземпляр:

x= 0 
def fun1(): 
    x= 1 
    def fun2(): 
     x= 2 
     def fun3(): 
      return x 
     return fun3() 
    return fun2() 
print fun1(), x 

2 0 

fun3 видит экземпляр х из ближайшей содержащей сферы, которая является областью видимости функции, связанной с fun2. Но другие случаи x, определенные в fun1 и глобально, не затрагиваются.

Перед тем, как nested_scopes - в Python pre-2.1 и в 2.1, если вы специально не запрашиваете эту функцию с использованием областей from-future-import - fun1 и fun2, не видны fun3, поэтому ответ S.Lott держится, и вы получить глобальную х:

0 0 
20

Правила обзора для Python 2.x уже изложены в других ответах. Единственное, что я хотел бы добавить, это то, что в Python 3.0 существует также концепция нелокальной области (обозначается ключевым словом «нелокальное»). Это позволяет вам напрямую обращаться к внешним областям и открывает возможность делать некоторые аккуратные трюки, включая лексические закрытия (без уродливых хаков, связанных с изменяемыми объектами).

EDIT: Вот PEP с дополнительной информацией об этом.

128

По сути, единственное, что в Python, которое вводит новую область видимости, - это определение функции. Классы - это немного особый случай, поскольку все, что определено непосредственно в теле, помещается в пространство имен класса, но они не доступны непосредственно из методов (или вложенных классов), которые они содержат.

В вашем примере есть только 3 областей, где будет осуществлять поиск х в: объем

  • цами - содержащий все определено в code3 и code5 (а также code4, ваша переменная цикла)

  • Глобальный охват - содержащий все, что определено в коде1, а также Foo (и любые изменения после него)

  • Пространство имен builtins. Немного специального случая - это содержит различные встроенные функции и типы Python, такие как len() и str().Как правило, это не должно изменяться никаким кодом пользователя, поэтому ожидайте, что он будет содержать стандартные функции и ничего больше.

Больше областей появляется только при введении в изображение вложенной функции (или лямбда). Они будут вести себя так, как вы ожидали. Вложенная функция может получить доступ ко всем в локальной области, а также к любой области приложения. например.

def foo(): 
    x=4 
    def bar(): 
     print x # Accesses x from foo's scope 
    bar() # Prints 4 
    x=5 
    bar() # Prints 5 

Ограничения:

Переменные в отличных от переменных локальной функции могут быть доступны областей, но не может быть отскок к новым параметрам без дополнительного синтаксиса. Вместо этого назначение создаст новую переменную вместо того, чтобы влиять на переменную в родительской области. Например:

global_var1 = [] 
global_var2 = 1 

def func(): 
    # This is OK: It's just accessing, not rebinding 
    global_var1.append(4) 

    # This won't affect global_var2. Instead it creates a new variable 
    global_var2 = 2 

    local1 = 4 
    def embedded_func(): 
     # Again, this doen't affect func's local1 variable. It creates a 
     # new local variable also called local1 instead. 
     local1 = 5 
     print local1 

    embedded_func() # Prints 5 
    print local1 # Prints 4 

Для того, чтобы действительно изменить привязки глобальных переменных внутри функции объема, необходимо указать, что переменная является глобальной с глобальным ключевым словом. Например:

global_var = 4 
def change_global(): 
    global global_var 
    global_var = global_var + 1 

В настоящее время не существует способа сделать то же самое для переменных в ограждающих функции областей, но Python 3 вводит новое ключевое слово, «nonlocal», который будет действовать аналогичным образом на глобальном, но и для вложенные функции.

78

Не было никакого тщательного ответа относительно времени Python3, поэтому я сделал здесь ответ.

Как указано в других ответах, существует 4 основных области применения, LEGB, для локальных, закрывающих, глобальных и встроенных. В дополнение к этому существует специальный диапазон, класс, который не содержит охватывающей области для методов, определенных в классе; любые присваивания внутри тела класса делают переменную оттуда связанной с телом в классе.

В частности, нет инструкция блока, кроме 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 в списках не создается также область видимости (в то время как генераторы и диктовки понимают!) Вместо того, чтобы они протекли значение в функции или глобальный масштаб:

>>> [ 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) # UnboundLocalError! 
    x += 1 # assignment here makes x a local variable! 

Область может заявить, что она явно хочет изменить глобальную переменную (модуль сфера), с глобальным ключевым словом:

x = 5 
def foobar(): 
    global x 
    print(x) # -> 5 
    x += 1 

foobar() 
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()  # -> print 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. 

любых переменный, не считается локальным для текущей области или любой охватывающей области, является глобальной переменной. Глобальное имя просматривается в глобальном словаре модуля; если он не найден, глобальный отображается с модуля встроенных модулей; имя модуля было изменено с python 2 на python 3; в python 2 это было __builtin__, а в python 3 теперь называется builtins. Если вы назначаете атрибут модуля встроенных модулей, после этого он будет отображаться в любом модуле как читаемая глобальная переменная, если только этот модуль не тени их собственной глобальной переменной с тем же именем.


Чтение встроенного модуля также может быть полезным; предположим, что вы хотите использовать функцию печати в стиле python 3 в некоторых частях файла, но в других частях файла по-прежнему используется оператор print, если ваша версия python равна> = 2.6, вы можете получить новую функцию стиля, как:

import __builtin__ 

print3 = __builtin__.__dict__['print'] 

from __future__ import print_function фактически не импортирует функции print где-нибудь в Python 2 - вместо этого он просто отключает правила синтаксического анализа для print оператора в текущем модуле, обработки print как любой другой идентификатор переменной, и, таким образом, функция print будет искать в встроенных функциях.

18

Несколько более полный пример объема:

from __future__ import print_function # for python 2 support 

x = 100 
print("1. Global x:", x) 
class Test(object): 
    y = x 
    print("2. Enclosed y:", y) 
    x = x + 1 
    print("3. Enclosed x:", x) 

    def method(self): 
     print("4. Enclosed self.x", self.x) 
     print("5. Global x", x) 
     try: 
      print(y) 
     except NameError as e: 
      print("6.", e) 

    def method_local_ref(self): 
     try: 
      print(x) 
     except UnboundLocalError as e: 
      print("7.", e) 
     x = 200 # causing 7 because has same name 
     print("8. Local x", x) 

inst = Test() 
inst.method() 
inst.method_local_ref() 

выход:

1. Global x: 100 
2. Enclosed y: 100 
3. Enclosed x: 101 
4. Enclosed self.x 101 
5. Global x 100 
6. global name 'y' is not defined 
7. local variable 'x' referenced before assignment 
8. Local x 200 
Смежные вопросы