自学内容网 自学内容网

闭包函数的基础知识

上期文章
1. 函数装饰器

2.闭包

2.1变量作用域

python有3种变量作用域

  • 模块全局作用域:在类或函数外部分配定义的。
  • 函数局部作用域:通过参数或者在函数主体中定义的。
  • 第3种作用域:闭包中的变量环境

2.2全局变量和局部变量

def fun(a):
    print(a)
    print(b)

fun(10)
10



---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

Cell In[4], line 5
      2     print(a)
      3     print(b)
----> 5 fun(10)


Cell In[4], line 3, in fun(a)
      1 def fun(a):
      2     print(a)
----> 3     print(b)


NameError: name 'b' is not defined

在函数 fun(a) 中打印局部变量a 和未知变量b,这里b没有绑定,所以报错
修改如下

def fun(a):
    print(a)
    # 这里是一个只读变量,先从局部域没有找到,再从全局域找到b
    print(b)
    
# 先绑定全局变量b 再调用fun(10)就没问题了
b = 5
fun(10)

另一个例子:

# 定义全局变量 b并绑定
b =5
def fun(a):
    print(a)
    # 打印一个还未绑定的局部变量,肯定会报错
    print(b)
    # 这里又定义了局部变量b,编译器会认为b是局部变量
    b=9
    
fun(10)

在函数fun(a)中,先打印a,没问题,因为a是一个参数(数据局部变量)
接着打印b时报错说是不能访问局部变量b,因为b=9在print(b)之后定义,而且并未查找全局变量b

python不要求声明变量,但是它会假定在函数主题中赋值的变量是局部变量。

我们本意是想在函数中访问全局变量b,如果想在函数中把b当成全局变量,就要使用global关键字声明b
修改如下:

b =5
def fun(a):
    # 使用全部变量b,可读写
    global b
    print(a)
    print(b)
    b=9
    
fun(10)

2.3闭包

闭包是一个函数嵌套另一个函数的形式,如下:

def closer():
    #没有赋值,本身又是一个可变类型
    value = []
    def fun(a):
        value.append(a)
        total = sum(value)
        return total / len(value)
    return fun

#调用closer()返回 fun函数引用
avg = closer()
#调用avg = fun函数引用,此时注意closer作用域已经“消失了”
#但是 自由变量 value引用依然存在
avg(10)
#连续调用发现value作用域一直存在
avg(40)
avg(15)
    

fun函数中引用的非全局变量(value),和局部变量(a,total) 来自于外部函数 closer()的作用域。这种形式的嵌套函数就叫闭包。
这种闭包函数隐藏了一些数据比如(value),value是 自由变量:指未在局部作用域中绑定的变量(即没有赋值)

综上所述:闭包是一个函数,它保留了定义函数时存在的自由变量的绑定。再调用函数avg时,虽然closer作用域不可用了,但是仍能访问那些绑定(value)

2.4 nonlocal

我们将上面的例子修改一下:

def closer():
    #绑定具体数值,本身又是不可变类型
    count = 0
    total = 0

    def fun(a):
        #这里会把count total 理解为局部变量(fun内部)
        count = count +1
        total = total + a
        return total / count
        
    return fun
    
#调用closer()返回 fun函数引用
avg = closer()

avg(10)
avg(40)
avg(15)

上面问题是在closer函数中定义的count = 0 total = 0已经有了绑定对象,他们不是自由变量
在fun函数中对count赋值,将重新创建count局部变量,因为没有提前定义,所以报错。
我们使用nonlocal声明count,total即可解决此问题,表示fun函数访问的是他的外部函数的变量,将他们变为自由变量。

def closer():
    count = 0
    total = 0

    def fun(a):
        #告诉编译器我使用的是外部变量 count total(closer函数域的)
        nonlocal count,total
        count = count +1
        total = total + a
        return total / count
        
    return fun
    
#调用closer()返回 fun函数引用
avg = closer()

avg(10)
avg(40)
avg(15)

原文地址:https://blog.csdn.net/bai_yechuang2012/article/details/144300605

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!