Python实战基础12-闭包

1、函数的嵌套调用

def testB():
    print('-------testB start------')
    print('这里是testB函数执行的代码……')
    print('-------testB end ------')

def testA():
    print('-----testA start-----')
    testB()
    print('-----testA end------')
testA()

运行结果:

Python实战基础12-闭包_第1张图片

总结:

  • 一个函数里面又调用了另外一个函数,这就是所谓的函数嵌套调用Python实战基础12-闭包_第2张图片
  • 如果函数A中,调用了另外一个函数B,那么先把函数B中的任务都执行完毕之后才会回到上次函数A执行的位置。 

 2、闭包

函数只是一段可执行代码,编译后就”固化“了,每个函数在内存中只有一份实例,得到函数的入口点便可以执行函数了。

函数还可以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题。

2.1 函数嵌套

在函数里面还可以定义函数,可以嵌套多层,执行需要被调用。

def outer():
    print('outer----hello')
    def inner():  # inner这个函数是在outer函数内部定义的
        print('inner-----hello')
    inner() # inner函数z只在outer函数内部可见
outer()
# inner() 这里会报错,在outer函数外部无法访问到inner函数
def outer():
    a = 100

    def inner():
        b = 200
        # b += a  # 内部函数可以使用外部函数的变量
        nonlocal a # 如果想修改外部函数的变量,需要在内部函数中添加:nonlocal
        a += b # 内部函数不能修改外部函数的变量
        print('我是内部函数',b)

    # result = locals() # locals()表示查看函数中的局部变量,以字典的形式返回。
    # print(result)

    print(a)
    # print(inner)
    # 调用inner
    inner()

outer()

  检索顺序:内层函数----》外层函数---》全局---》系统 builtins

2.2 什么是闭包

闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数体+引用环境)。

'''
闭包:
1.嵌套函数
2.内部函数引用了外部函数的变量
3.返回值是内部函数
'''

def outer(n):
    num = n
    def inner():
        return num+1
    return inner

print(outer(3)())  # 4
print(outer(5)())  # 6

在这段程序中,函数inner是函数outer的内嵌函数,并且inner函数是outer函数的返回值。

我们注意到一个问题:内嵌函数inner中引用到外层函数中的局部变量num,Python解释器会怎么处理这个问题呢?

先看这段代码的运行结果,当我们调用分别由不同的参数调用outer函数得到的函数时,得到的结果是隔离的(相互不影响),也就是说每次调用outer函数后都将生成并保存一个新的局部变量num,这里outer函数返回的就是闭包。

如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

闭包在使用装饰器的时候使用。

2.3 修改外部变量的值

闭包里默认不能修改外部变量。

def outer(n):
    num = n
    def inner():
        num = num + 1
        return num
    return inner

print(outer(1)())

上述代码运行时会报错!

UnboundLocalError: local variable 'num' referenced before assignment

原因分析

在python中,只要看到了赋值语句,就会认为赋值语句的左边是一个局部变量。

num = num+1这段代码里,num在= 的左边,python解析器会认为我们要修改inner函数里num这个局部变量,而这个变量使用之前是未声明的,所以会报错。

解决方案

报错的原因在于当我们在闭包内修改外部变量时,会被python解析器误会为内部函数的局部变量。所以,解决方案就是要让解析器知道不是要修改局部变量,而是要修改外部变量

解决方法:使用nonlocal关键字

def outer(n):
    num = n
    def inner():
        nonlocal num # 修改前使用nonlocal关键字对num变量进行说明
        num = num + 1
        return num
    return inner

print(outer(1)())

 

你可能感兴趣的:(python基础,python)