Нелокальное утверждение Python

При чем тут Питон nonlocal заявление сделать (в Python 3.0 и позже)?

Там нет документации на официальном сайте Python и help("nonlocal") тоже не работает.

10 ответов

Решение

Сравните это, не используя nonlocal:

x = 0
def outer():
    x = 1
    def inner():
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 1
# global: 0

На это, используя nonlocal, где inner() "s x сейчас тоже outer() "s x:

x = 0
def outer():
    x = 1
    def inner():
        nonlocal x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 2
# global: 0

Если бы мы должны были использовать global это будет связывать x к правильно "глобальному" значению:

x = 0
def outer():
    x = 1
    def inner():
        global x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 1
# global: 2

Короче говоря, он позволяет присваивать значения переменной во внешней (но не глобальной) области. См PEP 3104 для всех кровавых деталей.

Поиск в Google по запросу "python nonlocal" обнаружил предложение PEP 3104, которое полностью описывает синтаксис и обоснование этого утверждения. короче говоря, он работает точно так же, как global оператор, за исключением того, что он используется для ссылки на переменные, которые не являются ни глобальными, ни локальными для функции.

Вот краткий пример того, что вы можете сделать с этим. Счетчик генератора может быть переписан, чтобы использовать его так, чтобы он больше походил на идиомы языков с замыканиями.

def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

Очевидно, вы можете написать это как генератор, например:

def counter_generator():
    count = 0
    while True:
        count += 1
        yield count

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

@ooboo:

Требуется тот, который "ближе всего" к исходной точке исходного кода. Это называется "Лексическое определение объема" и является стандартным для>40 лет.

Члены класса Python действительно в словаре под названием __dict__ и никогда не будет достигнут лексическим ограничением.

Если вы не укажете nonlocal но делай x = 7, он создаст новую локальную переменную "x". Если вы укажете nonlocal, он найдет "ближайший" "х" и присвоит ему. Если вы укажете nonlocal и нет "х", это даст вам сообщение об ошибке.

Ключевое слово global мне всегда казалось странным, так как он с радостью игнорирует все остальные "х", кроме самого внешнего. Weird.

помощь ("нелокальная") nonlocal заявление


    nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*

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

Имена, перечисленные в nonlocal заявление, в отличие от перечисленных в global оператор, должен ссылаться на ранее существовавшие привязки во вложенной области (область, в которой должна быть создана новая привязка, не может быть определена однозначно).

Имена, перечисленные в nonlocal Оператор не должен вступать в противоречие с ранее существовавшими привязками в локальной области видимости.

Смотрите также:

PEP 3104 - доступ к именам во внешних областях
Спецификация для nonlocal заявление.

Связанные разделы справки: глобальный, NAMESPACES

Источник: Python Language Reference

Цитата из Python 3

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

Как сказано в ссылке, в случае нескольких вложенных функций изменяется только переменная в ближайшей вмещающей функции:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        x = 2
        innermost()
        if x == 3: print('Inner x has been modified')

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Inner x has been modified

"Ближайшая" переменная может находиться на расстоянии нескольких уровней:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Outer x has been modified

Но это не может быть глобальная переменная:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    inner()

x = 0
outer()
if x == 3: print('Global x has been modified')

# SyntaxError: no binding for nonlocal 'x' found
a = 0    #1. global variable with respect to every function in program

def f():
    a = 0          #2. nonlocal with respect to function g
    def g():
        nonlocal a
        a=a+1
        print("The value of 'a' using nonlocal is ", a)
    def h():
        global a               #3. using global variable
        a=a+5
        print("The value of a using global is ", a)
    def i():
        a = 0              #4. variable separated from all others
        print("The value of 'a' inside a function is ", a)

    g()
    h()
    i()
print("The value of 'a' global before any function", a)
f()
print("The value of 'a' global after using function f ", a)

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

В документации сказано ниже:

Оператор nonlocal заставляет перечисленные идентификаторы ссылаться на ранее связанные переменные в ближайшей охватывающей области, исключая глобальные. ...

Так, например,nonlocal fooвinner()может получить доступ к нелокальной переменной foo = 10вmiddle()но не нелокальная переменная foo = 5in или глобальная переменная foo = 0снаружиouter()как показано ниже:

      foo = 0 # <- ✖
def outer():
    foo = 5 # <- ✖
    def middle():
        foo = 10 # <- 〇
        def inner():
            nonlocal foo # Here
            foo += 1
            print(foo) # 11
        inner()
    middle()
outer()

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

a = 10
def Outer(msg):
    a = 20
    b = 30
    def Inner():
        c = 50
        d = 60
        print("MU LCL =",locals())
        nonlocal a
        a = 100
        ans = a+c
        print("Hello from Inner",ans)       
        print("value of a Inner : ",a)
    Inner()
    print("value of a Outer : ",a)

res = Outer("Hello World")
print(res)
print("value of a Global : ",a)
Другие вопросы по тегам