Python嵌套函数与nonlocal

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Python嵌套函数与nonlocal

weixin_42576837   2022-09-29 我要评论

理解闭包之前,我们首先需要理解什么是嵌套函数(nested functions)以及非局部(nonloca)关键字

嵌套函数

  • 在另一个函数中定义的函数称为嵌套函数。
  • 嵌套函数可以访问 这个封闭范围域内的 变量。
  • 在python中,这些非局部变量只可以在他们的作用域范围内访问。

嵌套函数的例子:

#Python program to illustrate
#nested functions
def outerFunction(text):
    text = text
    #该函数定义在函数之内,作为一个内部函数
    def innerFunction():
        print(text)
    #out函数中,调用这个内部函数
    innerFunction()
if __name__ == '__main__':
    outerFunction('Hey !')

嵌套函数中变量的范围

在一个函数中访问全局变量之前已经说过了,但是怎么在一个内部函数中访问外部函数的变量?

def f1():
    #f1的变量
    s = 'hello'
    def f2():
        #f2()内部使用f1的变量
        print(s)
    f2()
f1()

这种访问方式和 函数内访问全局变量很类似。

现在我想要在内部函数改变外部函数的变量要怎么做?

def f1():
    #f1的变量
    s = 'hello'
    def f2():
        #f2()内部试图改变f1的变量
        s = 'hi hi hi'
        print(s)
    f2()
    print(s)
#调用f1()
f1()

f2()内部通过s = 'hi hi hi' 试图将外部函数的变量值s改变。

但是其实是在f2()内部重新创建了一个新的变量也叫s,所以完全不会对外部的s有影响。

这和函数内部改变全局变量是类似的,不加global,只是创建了一个同名变量。

那么同样使用global行不行?

def f1():
    #f1的变量
    s = 'hello'
    def f2():
        #f2()内部试图使用global改变f1的变量
        global s
        s = 'hi hi hi'	#实际是在f2()中创建了一个全局变量
        print(s)
    f2()
    print(s)
#调用f1()
f1()

结果是完全没有变化的,

global s实际上是在f2()内部声明s是一个全局变量,是整个程序都可以使用的,它和f1()中的s不是同一个。我们可以在函数外输出它:

那么如何通过内部函数改变外部函数的变量值呢?其中一种方法是使用nonlocal关键字:

def f1():
    #f1的变量
    s = 'hello'
    def f2():
        #f2()使用nonlocal改变f1的变量
        nonlocal s
        s = 'hi hi hi'
        print(s)
    f2()
    print(s)
#调用f1()
f1()

在f2()函数内部成功的修改了f1()函数中的变量s的值

nonlocal

nonlocal 关键字被用来在最近的范围域中引用变量, 在局部变量和全局变量上使用不起作用,用于在全局范围和本地局部范围之外的另一个范围内引用变量。nonlocal关键字常常被用在嵌套函数中引用 父函数中的变量。

使用nonlocal的优点

  • 帮助我们访问上层作用域中的变量
  • 引用的变量被重复使用,因此该变量的内存地址也被重复适使用,所以可以将局部变量保存在内存中

缺点

  • nonloca关键字不可以用来引用全局变量和局部变量
  • nonloca关键字只能用在嵌套结构中

举例

使用nonlocal关键字修改父函数中的变量

def foo():
    name = 'hello'
    def  bar():
        nonlocal name #修改父函数的变量
        name = 'hi hi'
        print(name)
    #调用bar()
    bar()
    #父函数foo()内输出name
    print(name)
#调用foo()
foo()

如果使用nonlocal 修改全局变量会怎么样?

#全局变量
global_name = 'hello'
#外部函数
def f1():
    #内部函数
    def f2():
        #使用nonlocal 声明,尝试使用nonlocal 引用全局变量
        nonlocal global_name
        global_name = 'hi hi'#尝试 修改 
        print(global_name)
    
    #掉用f2()
    f2()
f1()
print(global_name)

报错信息显示:没有叫做global_namenonlocal变量,这是因为:

nonlocal是用在嵌套结构中,用来引用父函数中的局部变量的,但是父函数f1()中没有叫做global_name的局部变量,对于函数外部的全局变量global_name来说,使用nonlocal是无法引用的,所以python解释器找不到global_name,自然出错。

多层嵌套中的nonlocal

def f1():
    name = 'f1'
    def f2():
        name = 'f2'
        def f3():
            #nonlocal 修改父函数的变量,即f2()的name
            nonlocal name
            print(name)  #输出f2  使用的是f2中的name
            name = 'f3' #对f2中的name修改
            print(name) #输出f3 修改成功
        f3()
        print(name)#输出f3,虽然是f2中的name,但是在f3中修改了
    f2()
    print(name)#输出f1,f1的name,没有被使用
f1()

所以在多层嵌套的结构成,nonlocal关键字会寻找最近的上层,也就是父函数,而不是更上层的爷爷函数。

嵌套函数中局部变量的重用

def counter():
    #c是局部变量
    c = 0
    def count():
        #使用上层函数中的c
        nonlocal c
        c += 1
        return c
    return count

调用外部counter()函数,正常来说,函数调用结束后,内部的局部变量会被销毁,但是由于counter()内部嵌套的count()使用了nonlocal来使用父函数的局部变量c,所以c是被重用了,即使外层函数调用结束了,c并没有被销毁。

参考:

Python Inner Functions

Python nonlocal Keyword

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们