Python非本地语句

oob*_*boo 293 python closures global python-nonlocal

Python nonlocal语句做了什么(在Python 3.0及更高版本中)?

官方Python网站上没有文档,help("nonlocal")也没有用.

Ano*_*non 415

比较这个,不使用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
Run Code Online (Sandbox Code Playgroud)

对此,使用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
Run Code Online (Sandbox Code Playgroud)

如果我们要使用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
Run Code Online (Sandbox Code Playgroud)

  • 它非常相似 - 但请注意外部x在示例中不是全局的,而是在外部函数中定义. (44认同)
  • 这与全球x有何不同? (28认同)
  • 如果有 3 个嵌套函数怎么办?那么有没有办法从最里面的函数访问所有 4 个级别呢? (7认同)
  • @Dustin - 实际上,如果你的A类中定义了属性x和子类B,你可以将B中的x称为Ax (3认同)
  • @ tommy.carstensen你可以把这个函数作为一个arg来传递,这是高阶函数的美妙之处.此外,在函数式编程中,这称为组合,python不是纯FP语言,但你当然可以使用一些特性(生成器,高阶函数是一些例子) (3认同)
  • 在定义内部函数时,代码很容易大量缩进,最终违反了79个字符PEP8建议.有什么方法可以解决这个问题吗?内部函数能以某种方式放在外部函数之外吗?我知道这个问题听起来很愚蠢,但我很认真. (2认同)

Ark*_*ady 80

简而言之,它允许您为外部(但非全局)范围内的变量赋值.有关所有血腥细节,请参阅PEP 3104.


Sin*_*ion 39

谷歌搜索"python nonlocal"出现了Proposal,PEP 3104,它完整地描述了该声明背后的语法和推理.简而言之,它的工作方式与global语句完全相同,不同之处在于它用于引用既不是全局也不是函数本地的变量.

以下是您可以使用此功能的简要示例.可以重写计数器生成器以使用它,使其看起来更像是带闭包的语言的习语.

def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter
Run Code Online (Sandbox Code Playgroud)

显然,你可以把它写成一个生成器,如:

def counter_generator():
    count = 0
    while True:
        count += 1
        yield count
Run Code Online (Sandbox Code Playgroud)

不过,虽然这是完全地道的蟒蛇,它似乎是第一个版本将是初学者更明显一点.通过调用返回的函数正确使用生成器是一个常见的混淆点.第一个版本显式返回一个函数.

  • 关于全局的事情是它只适用于全局变量.它无法在封闭的非全局范围内看到变量. (5认同)

小智 14

@ooboo:

它与源代码中的参考点"最接近".这被称为"词汇范围",现在是标准的> 40年.

Python的类成员实际上是在一个被称为字典的字典中,__dict__并且永远不会被词法范围所覆盖.

如果您没有指定nonlocal但是x = 7,它将创建一个新的局部变量"x".如果你指定nonlocal,它将找到"最接近的""x"并分配给它.如果您指定nonlocal并且没有"x",它将显示错误消息.

关键字global对我来说似乎总是很奇怪,因为除了最外面的关键字之外,它会高兴地忽略所有其他"x".奇怪的.


小智 14

帮助('nonlocal')nonlocal声明


    nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*
Run Code Online (Sandbox Code Playgroud)

nonlocal语句使列出的标识符引用最近的封闭范围中先前绑定的变量.这很重要,因为绑定的默认行为是首先搜索本地名称空间.除了全局(模块)范围之外,该语句还允许封装代码重新绑定局部范围之外的变量.

nonlocal与语句中列出的名称不同,语句中 列出的名称global必须引用封闭范围中的预先存在的绑定(无法明确确定应创建新绑定的范围).

nonlocal声明中列出的名称不得与本地作用域中的预先存在的绑定冲突.

也可以看看:

PEP 3104 - 访问外部范围中
的名称nonlocal声明的规范.

相关帮助主题:global,NAMESPACES

来源:Python语言参考

  • 每天学些新东西.我不知道你可以在关键字上使用`help()`(现在我的想法被吹了:`help()`没有参数_interactive_). (9认同)

Jey*_*mon 5

引用《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
Run Code Online (Sandbox Code Playgroud)

“最近”变量可以相隔几个级别:

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
Run Code Online (Sandbox Code Playgroud)

但是它不能是全局变量:

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
Run Code Online (Sandbox Code Playgroud)