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

Какие именно правила области Python?

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

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

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

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

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

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

Ответ 1

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

Правило LEGB

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

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

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

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

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

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

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

  • L: Локальный в def spamcode3, code4 и code5)
  • E: Любые включающие функции (если весь пример был в другом def)
  • G: Был ли какой-либо x объявлен глобально в модуле (в code1)?
  • B: Любой встроенный x в Python.

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

Ответ 2

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

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

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

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

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

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

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

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

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

global_var1 = []
global_var2 = 1

def func():
    # This is OK: It 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 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

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

Ответ 3

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

Как указано в других ответах, есть 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.

Любая переменная, которая не считается локальной для текущей области или любой включающей области, является глобальной переменной. Глобальное имя ищется в глобальном словаре модуля; если он не найден, глобальный объект ищется из встроенного модуля; название модуля было изменено с 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 просматривать поиск во встроенных.

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

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

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

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

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

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

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

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

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

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

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

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

См. Правила области Python, область Python, область переменных.

Ответ 7

Где x найдено?

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

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

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

lambda ничем не отличается от 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, если вы специально не запрашиваете эту функцию с использованием областей from-future-import - fun1 и fun2, не видны fun3, поэтому ответ S.Lott держится, и вы получите глобальный x:

0 0

Ответ 8

В Python

любая переменная, которой назначено значение, является локальной для блока, в котором появляется назначение.

Если переменная не может быть найдена в текущей области, пожалуйста, обратитесь к порядку LEGB.