Python中闭包的理解

Python中闭包的理解:

Num01–>定义:

官方定义: 闭包是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数,这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

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

举一个简单的例子来说明:

def addx(x):
    def addy(y):
        return x + y
    return addy
xy = addx(6)
print(type(xy))
print(xy.__name__)
print(xy(66))
# 结果是:
# <class 'function'>
# addy
# 72

对以上代码加以说明:
如果在一个内部函数里:addy(y)就是这个内部函数。
对在外部作用域(但不是全局作用域)的变量进行引用:x就是被引用的变量,x在外部作用域addx(x)函数里,但不在全局作用域里。
那么这个内部函数addy(y)就是闭包。

闭包的_closure_属性

一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。在Python中,所谓的闭包是一个包含有环境变量取值的函数对象。环境变量取值被保存在函数对象的_closure_属性中。
如下案例加以说明:

b = 5

def line_func():
    b = 55

    def line(x):
        return 2 * x + b

    return line


my_line = line_func()
print(my_line.__closure__)
print(my_line.__closure__[0].cell_contents)
# 结果如下:
# (<cell at 0x0000028F6E228C18: int object at 0x00000000508A0890>,)
# 55

对以上代码加以说明:
_closure_里面包含了一个元组。元组中每一个对象类型都是cell类型的。元组中的第0个元素就是55,也就是创建闭包时的环境变量b的取值。

Num02–>为什么要使用闭包

    不同的是闭包本身就是个方法。和类一样,我们在编程时经常会把通用的东西抽象成类,以复用通用的功能。闭包也是一样,当我们需要函数粒度的抽象时,闭包就是一个很好的选择。

    在这点上闭包可以被理解为一个只读的对象,你可以给他传递一个属性,但它只能提供给你一个执行的接口。因此在程序中我们经常需要这样的一个函数对象——闭包,来帮我们完成一个通用的功能。

Num03–>使用闭包注意事项

Test01–>闭包中是不能修改外部作用域局部变量的值

看如下案例:

def func():
    m = 0

    def func_in():
        m = 1
        print("++%d" % m)

    print("--%d" % m)
    func_in()
    print("==%d" % m)


print("最后打印:%s" % func())
# 结果如下:
# --0
# ++1
# ==0
# 最后打印:None

对以上代码加以说明:
从执行结果可以看出,虽然在闭包里面也定义了一个变量m,但是其不会改变外部函数中的局部变量m的值。

Test02–>局部变量的问题

def foo():
    a = 1

    def bar():
        a = a + 1
        return a

    return bar
f=foo()
print(f())
# 结果如下:
# Traceback (most recent call last):
#   File "E:/pycharmProject/Test24.py", line 82, in <module>
#     print(f())
#   File "E:/pycharmProject/Test24.py", line 77, in bar
#     a = a + 1
# UnboundLocalError: local variable 'a' referenced before assignment

以上代码加以说明:
这是因为在执行代码 f = foo()时,Python会导入全部的闭包函数体bar()来分析其的局部变量。Python规则指定所有在赋值语句左面的变量都是局部变量,则在闭包bar()中,变量a在赋值符号”=”的左面,被Python认为是bar()中的局部变量。再接下来执行print(f())时,程序运行至a = a + 1时,因为先前已经把a归为bar()中的局部变量,所以python会在bar()中去找在赋值语句右面的a的值,结果找不到,就会报错。

两种解决办法

#第一种解决办法:自由变量为不可变对象
def foo():
    a = 1

    def bar():
        nonlocal a
        a = a + 1
        return a

    return bar
f=foo()
print(f())

#第二种解决办法:不是太好,不建议,自由变量为可变对象
def foo():
    a = [1]
    def bar():
        a[0] = a[0] + 1
        return a[0]

    return bar
f=foo()
print(f())

Test03–>Python函数式编程中一个问题

看如下代码:

for a in range(10): 
    print(i)

在程序里面经常会出现这类的循环语句,Python的问题就在于:当循环结束以后,循环体中的临时变量a不会销毁,而是继续存在于执行环境中

还有一个Python的现象是:Python的函数只有在执行时,才会去找函数体里的变量的值。


listname = []
for a in range(3):
    print("a==%s" % a)
    def foo(x):
        print("a--%s" % a)
        print(x + a)
        print("a++%s" % a)
    listname .append(foo)
for f in listname :
    f(2)
# 看结果是:
# a==0
# a==1
# a==2
# a--2
# 4
# a++2
# a--2
# 4
# a++2
# a--2
# 4
# a++2

可能有些人认为这段代码的执行结果应该是2,3,4.但是实际的结果是4,4,4。这是因为当把函数加入flist列表里时,Python还没有给a赋值,只有当执行时,再去找a的值是什么。这时在for循环语句中,已经将a的值赋值为2,所以以上代码的执行结果是4,4,4。

如果要想结果是2,3,4,看如下代码修改:

listname = []
for a in range(3):
    print("a==%s" % a)
    def foo(x, y=a):
        print("a==%s" % a)
        print("y--%s" % y)
        print(x + y)
        print("y++%s" % y)
        print("a==%s" % a)
    listname.append(foo)
for f in listname:
    f(2)
# 看结果是:
# a==0
# a==1
# a==2
# a==2
# y--0
# 2
# y++0
# a==2
# a==2
# y--1
# 3
# y++1
# a==2
# a==2
# y--2
# 4
# y++2
# a==2

相信读者看到这里就能明白函数式编程的特点了。

Num04–>闭包的作用

作用1:当闭包执行完后,仍然能够保持住当前的运行环境。
作用2:闭包可以根据外部作用域的局部变量来得到不同的结果。
作用3:闭包对数据的持久化以及按配置产生不同的功能,是很有帮助的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值