类十三 发表于 2018-9-22 16:55:49

python3.6 官方文档上nonlocal和global 一个例子的疑问

源代码:
def scope_test():
    def do_local():
      spam = "local spam"

    def do_nonlocal():
      nonlocal spam
      spam = "nonlocal spam"

    def do_global():
      global spam
      spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)

输出的结果为:
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

疑问:
def scope_test():
    def do_local():
      spam = "local spam"

    def do_nonlocal():
      nonlocal spam
      spam = "nonlocal spam"

    def do_global():
      global spam
      spam = "global spam"

    spam = "test spam"
   
    """
    疑问1:do_local并没有引用全局变量,为什么打印出来的是全局变量spam?即"test spam"
    这个函数不是该直接打印"local spam"吗?
    """
   
    do_local()
    print("After local assignment:", spam)
   
    """疑问2:我对do_nonlocal函数的理解是:用nonlocal导入了上一层的spam变量
      也就是do_local函数中的spam变量的值,然后该函数把这个spam重新赋值为"nonlocal spam"
      也就是说,执行了这个函数后,do_local函数中的spam也改变了。不知道是否理解正确"""
   
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    """
    疑问3:对do_global的理解:通过global引入全局变量,即"test spam",并将全局变量的spam
    重新赋值为"global spam",那么为什么最后打印出来的是"nonlocal spam"?
    """
    do_global()
    print("After global assignment:", spam)

scope_test()
"""最后一次打印的spam值为:global spam
    我认为是因为执行了do_nonlocal函数后被重新赋值了。
    所以我就最后一个spam稍微看懂了,其余就没明白,不知道各位大大有没有什么可以帮助我理解的?
"""
print("In global scope:", spam)

RIXO 发表于 2018-9-22 16:55:50

我把代码改成了这样,让你好理解
def scope_test():
    def do_local():
      spam = "local spam"

    def do_nonlocal():
      nonlocal spam
      spam = "nonlocal spam"

    def do_global():
      global spam
      spam = "global spam"

    spam = "test spam"
    print(id(spam))
    do_local()
    print("After local assignment:", id(spam))
    do_nonlocal()
    print("After nonlocal assignment:", id(spam))
    do_global()
    print("After global assignment:", id(spam))

scope_test()
print("In global scope:", id(spam))
输出结果为
2740280630256
After local assignment: 2740280630256
After nonlocal assignment: 2740280630128
After global assignment: 2740280630128
In global scope: 2740280630000

这样就好理解了,第一个spam 赋值是在函数 scope_test下的 是这个函数的局部变量
第一个函数是在自身函数下面建了一个spam局部变量,所以不会被打印
第二个函数是在自身函数下面建了一个可以在scope_test 和non_local函数里面使用的局部变量spam
第三个函数是在scope_test外面建立了一个全局变量spam
在do_global 函数执行后,spam并非直接在当前的函数里面创建的spam变量,而是在全局变量中又创建了一个变量
所以这个spam 和 函数中存在的几个spam都不一样
如果,而函数调用属性是这样的,先在函数自身的命名空间找变量名,如果有打印该变量值,然后在上一层命名空间中找如果有变量名,打印变量值,如果没有且在全局变量命名空间,报错
现在你知道do_global为什么返回的为“nonlocal spam”吧,因为在当前的函数命名空间下,已经有了一个叫spam的nonlocal变量名,就不会再去上一层空间找了

claws0n 发表于 2018-9-22 17:12:55

def scope_test():
    def do_local():
      spam = "local spam"

    def do_nonlocal():
      nonlocal spam
      spam = "nonlocal spam"

    def do_global():
      global spam
      spam = "global spam"

    ## 上面只是定义,不会执行,所以不会更改任何东西

    spam = "test spam"    ##现在才定义 spam
    do_local()                  ##调用函数。此函数的 spam 不是以参数的形式传入的,所以会去修改已经被定义的
    print("After local assignment:", spam)
    do_nonlocal()            ## 把局部变量转成 nonlocal,并且重新赋值
    print("After nonlocal assignment:", spam)
    do_global()               ##把nonlocal 变量转成 global,并且重新赋值
    print("After global assignment:", spam)

scope_test()    ##真正调用函数,才会执行上面的指令
print("In global scope:", spam)

类十三 发表于 2018-9-24 17:04:02

claws0n 发表于 2018-9-22 17:12


def do_global():
      global spam
      spam = "global spam"

do_global为什么返回的为“nonlocal spam”?
执行了该函数后,spam不是会被赋值为"global spam"么,不是应该返回这个?

claws0n 发表于 2018-9-25 12:12:51

本帖最后由 claws0n 于 2018-9-25 12:14 编辑

类十三 发表于 2018-9-24 17:04
do_global为什么返回的为“nonlocal spam”?
执行了该函数后,spam不是会被赋值为"global spam"么, ...

嗯,楼上大致描述了。
先讲这个概念 >>global(    local(    nonlocal    )    )
global 全局变量拥有最大的访问范围,可以透过 local 等访问,不能修改,修改的话要另外修饰。
加了 global 修饰之后,修改的是全局变量。如果没有该变量,则创建一个。应该说是覆盖吧。c = 10

def f():
    c += 2    ## 这样会报错,因为没有初始值
    print(c)    ## 如果只有这句,会打印 10,访问了全局变量

f()
你也许听过【堆栈】这个的东西,了解就好。函数被调用的时候,内存会跳转到另一个地方,从主函数切换到被调用的函数。函数被调用完后,又切换回来,所以局部变量会“消失”,就是这个原因。
现在的问题是,这个全局变量是定义在一个函数里的函数,所以,子函数结束后,变量会随着消失。那在子函数里定义的全局变量又要如何保存?方法就是放到另一个地方暂存,直到程序回到主函数的时候,才放回来。因此,出了 do_global() 之后,global spam 的记忆将在 scope_test() 里消失了。def do_global():
    global spam
    spam = "global spam"
    print("inside do_global", spam) ## 打印 "inside do_global global spam"
那 nonlocal 为什么不会消失呢?同样的操作模式,但nonlocal 是局部变量里的全局变量,在局部范围里,它为王。它的被访问域是 local,但它的记忆如同 global,直到程序结束后才释放,但它又不是 global,所以叫 nonlocal。
页: [1]
查看完整版本: python3.6 官方文档上nonlocal和global 一个例子的疑问