简体   繁体   English

Python 非局部语句/关键字

[英]Python nonlocal statement / keyword

What does nonlocal do in Python 3.x? nonlocal 在nonlocal 3.x 中做了什么?


To close debugging questions where OP needs nonlocal and doesn't realize it, please use Is it possible to modify variable in python that is in outer, but not global, scope?要关闭 OP 需要nonlocal但没有意识到的调试问题,请使用Is it possible to modify variable in python that is in outer, but not global, scope? instead.反而。

Although Python 2 is officially unsupported as of January 1, 2020 , if for some reason you are forced to maintain a Python 2.x codebase and need an equivalent to nonlocal , see nonlocal keyword in Python 2.x .尽管 Python 2从 2020 年 1 月 1 日起正式不受支持,但如果出于某种原因您被迫维护 Python 2.x 代码库并且需要等效于 nonlocal ,请参阅nonlocal 2.x 中的 nonlocal 关键字

Compare this, without using nonlocal :比较一下,不使用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

To this, using nonlocal , where inner() 's x is now also outer() 's x :为此,使用nonlocal ,其中inner()x现在也是outer()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

If we were to use global , it would bind x to the properly "global" value:如果我们使用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

In short, it lets you assign values to a variable in an outer (but non-global) scope.简而言之,它允许您将值分配给外部(但非全局)范围内的变量。 See PEP 3104 for all the gory details.有关所有血腥细节,请参阅PEP 3104

A google search for "python nonlocal" turned up the Proposal, PEP 3104 , which fully describes the syntax and reasoning behind the statement.谷歌搜索“python nonlocal”出现了提案, PEP 3104 ,它完全描述了语句背后的语法和推理。 in short, it works in exactly the same way as the global statement, except that it is used to refer to variables that are neither global nor local to the function.简而言之,它的工作方式与global语句完全相同,只是它用于引用既不是全局变量也不是函数局部变量。

Here's a brief example of what you can do with this.这是一个简短的示例,说明您可以使用它做什么。 The counter generator can be rewritten to use this so that it looks more like the idioms of languages with closures.可以重写计数器生成器以使用它,使其看起来更像带有闭包的语言的惯用语。

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

Obviously, you could write this as a generator, like:显然,您可以将其编写为生成器,例如:

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

But while this is perfectly idiomatic python, it seems that the first version would be a bit more obvious for beginners.但是,虽然这是完全惯用的 python,但似乎第一个版本对初学者来说会更明显一些。 Properly using generators, by calling the returned function, is a common point of confusion.通过调用返回的函数来正确使用生成器是一个常见的混淆点。 The first version explicitly returns a function.第一个版本显式返回一个函数。

It takes the one "closest" to the point of reference in the source code.它将“最接近”源代码中的参考点。 This is called "Lexical Scoping" and is standard for >40 years now.这被称为“词汇范围”,并且已经成为标准超过 40 年了。

Python's class members are really in a dictionary called __dict__ and will never be reached by lexical scoping. Python 的类成员实际上在一个名为__dict__的字典中,并且永远不会通过词法作用域来访问。

If you don't specify nonlocal but do x = 7 , it will create a new local variable "x".如果您不指定nonlocal但执行x = 7 ,它将创建一个新的局部变量“x”。 If you do specify nonlocal , it will find the "closest" "x" and assign to that.如果您确实指定了nonlocal ,它将找到“最接近的”“x”并分配给它。 If you specify nonlocal and there is no "x", it will give you an error message.如果您指定nonlocal并且没有“x”,它将给您一条错误消息。

The keyword global has always seemed strange to me since it will happily ignore all the other "x" except for the outermost one.关键字global对我来说一直很奇怪,因为它会很高兴地忽略除最外面的“x”之外的所有其他“x”。

help('nonlocal') The nonlocal statement help('nonlocal') nonlocal语句


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

The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope. nonlocal语句导致列出的标识符引用最近的封闭范围内的先前绑定的变量。 This is important because the default behavior for binding is to search the local namespace first.这很重要,因为绑定的默认行为是首先搜索本地命名空间。 The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope.该语句允许封装代码重新绑定全局(模块)范围之外的局部范围之外的变量。

Names listed in a nonlocal statement, unlike to those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).global语句中列出的名称不同, nonlocal语句中列出的名称必须引用封闭范围中的预先存在的绑定(无法明确确定应创建新绑定的范围)。

Names listed in a nonlocal statement must not collide with pre- existing bindings in the local scope. nonlocal语句中列出的名称不得与本地范围内的预先存在的绑定发生冲突。

See also:也可以看看:

PEP 3104 - Access to Names in Outer Scopes PEP 3104 - 访问外部范围内的名称
The specification for the nonlocal statement. nonlocal语句的规范。

Related help topics: global, NAMESPACES相关帮助主题:全局、命名空间

Source: Python Language Reference来源: Python 语言参考

Quote from the Python 3 Reference :引用Python 3 参考

The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. nonlocal 语句导致列出的标识符引用最近的封闭范围内的先前绑定的变量,不包括全局变量。

As said in the reference, in case of several nested functions only variable in the nearest enclosing function is modified:如参考资料中所述,在多个嵌套函数的情况下,仅修改最近的封闭函数中的变量:

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

The "nearest" variable can be several levels away: “最近”变量可以在几个级别之外:

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

But it cannot be a global variable:但它不能是全局变量:

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)

My personal understanding of the "nonlocal" statement (and do excuse me as I am new to Python and Programming in general) is that the "nonlocal" is a way to use the Global functionality within iterated functions rather than the body of the code itself.我个人对“非本地”语句的理解(请原谅,因为我是 Python 和一般编程的新手)是“非本地”是在迭代函数中使用全局功能而不是代码本身的一种方式. A Global statement between functions if you will.如果您愿意,可以在函数之间使用全局语句。

with 'nonlocal' inner functions(ie;nested inner functions) can get read & ' write ' permission for that specific variable of the outer parent function .使用“非本地”内部函数(即嵌套内部函数)可以获得外部父函数的特定变量的读取和“写入”权限。 And nonlocal can be used only inside inner functions eg: nonlocal 只能在内部函数内部使用,例如:

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)

The documentation says below: 文档如下:

The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. nonlocal 语句导致列出的标识符引用最近的封闭 scope 中先前绑定的变量,不包括全局变量。 ... ...

So for example, inner() can access the non-local variable x in middle() with nonlocal x but not the non-local variable x in outer() or the global variable x outside outer() as shown below:因此,例如, inner()可以使用非局部x访问middle()中的非局部变量nonlocal x ,但不能访问outer()的非局部变量x或 outer outer() ) 外部的全局变量x ,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM