Краткое описание правил определения области?


что ровно являются ли правила определения области Python?

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

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

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

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

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

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

7 394

7 ответов:

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

правило LEGB.

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

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

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

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

Итак, в случае

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

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

L: местный, в def spam (in code3,code 4,code5).

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

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

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

x никогда не будет найден в code2 (даже в случаи, когда вы могли бы ожидать, что это будет, см. ответ Антти или здесь).

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

в вашем примере есть только 3 области, где x будет искать в:

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

  • глобальная область-содержащая все, что определено в code1, а также 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. Например:

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

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

не было подробного ответа относительно времени 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)  # causes UnboundLocalError!
    x += 1    # because assignment here makes x a local variable within the function

# call the function
foobar()

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

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.

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


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

import __builtin__

print3 = __builtin__.__dict__['print']

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

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

редактировать: вот PEP С дополнительной информацией по этому.

немного более полный пример области:

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

Python разрешает ваши переменные с помощью -- как правило -- трех доступных пространств имен.

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

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

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

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

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

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

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

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

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

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

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

посмотреть Правила Области Python,Python Scope,Переменная.

где находится x?

x не найден, поскольку вы его не определили. :- ) Он может быть найден в code1 (глобальный) или code3 (локальный), если вы поместите его туда.

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

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

лямбда ничем не отличается от def. Если внутри функции используется лямбда, это то же самое, что и определение вложенной функции. В Python 2.2 и далее доступны вложенные области. В этом случае вы можете привязать x в любом уровень вложенности функций и 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 видит экземпляр x из ближайшей содержащей области, которая является областью действия, связанной с fun2. Но другие экземпляры x, определенные в fun1 и глобально, не затрагиваются.

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

0 0