python闭包

创建闭包的要求

在python中创建一个闭包一般有三个要求:
(1)闭包函数必须有内嵌函数。
(2)内嵌函数必须要引用外层函数的变量。
(3)闭包函数返回的必须是内嵌函数的引用地址。

def func():
    name='李四'
    def inner():
        print(name)
    # print(inner.__closure__)
    return inner       


f=func()
f()
'''
运行结果:

李四
'''

闭包函数与普通函数有什么不同呢?

我们先假设没有return inner这句话:当调用func()函数的时候为值’李四’开辟一片内存空间,并分配了内存地址,将’李四’的内存地址赋值给name。因为没有调用inner()函数,所以不会执行inner()函数,执行完函数,进行垃圾回收。但是当return 了inner的内存地址就会调用inner()函数打印里面的内容。这就是闭包函数。

闭包

我们可以提几个问题?
问题1:
如何判断是不是闭包函数?
使用closure()方法
方法用途:
判断是不是闭包函数,是则返回带cell元素,不是则返回None。
代码示例:

def func():
    name='李四'
    def inner():
        print(name)
    print("判断是不是闭包函数,是则返回带cell元素,不是则返回None")
    print(inner.__closure__)
    return inner

f=func()
f()
'''
运行结果:

判断是不是闭包函数,是则返回带cell元素,不是则返回None
(<cell at 0x000001C3D31CA528: str object at 0x000001C3D3202818>,)
李四
'''

问题二:
最后两行代码为什么不能用func()直接代替?
这是因为执行return的时候返回一个内存地址,大家都知道,要调用一个函数,只需要内存地址是不够的,还得加上()所以还可以这样写。
代码示例:

def func():
    name='李四'
    def inner():
        print(name)
    return inner

func()()

'''
运行时间:

李四
'''

如果直接是return 函数名那么就会如下,返回的是inner()函数的内存地址,那么打印的也内存地址,并没有调用inner()函数!
代码示例:

def func():
    name='李四'
    def inner():
        print(name)
    return inner
    
print(func())

'''
运行结果:

<function func.<locals>.inner at 0x0000027DB07838C8>
'''

延迟绑定

不得不提的一道题:
题目:问如下程序打印的是什么?

def fun():
    temp = [lambda x:i*x for i in range(4)]
    return temp
for i in fun():
    print(i(2),end=" ")

'''
运行结果;

6 6 6 6 
'''

分析:首先调用fun()函数,在列表中将匿名函数循环了4次,所以列表中记录了匿名函数的四次内存地址,注意:每次匿名函数的内存地址都是不一样的!并返回给调用者,使用for i in 进行遍历列表中的内存地址,调用列表中四个匿名函数的内存地址,并且将2对匿名函数进行传参,在匿名函数的局部变量域中找不到i,然后就会扩大范围到上一层去找,在fun()函数中找到了,是3,你会问为什么是3呢,因为循环早已进行完毕。所以每次调用匿名函数所用的i是同一个,皆为3,这也导致运行结果是6 6 6 6 因为2乘3等于6嘛,这便是延迟绑定。
初学小白可能遇到如下问题?
第一:
没有搞清楚这是如何将x值传进去的?
解答:你可能会说这个2怎么能传给fun()函数啊,这个函数并没有定义形参来接受,那你就大错特错了,2并不是传给fun()函数,而传的是列表中的匿名函数。
第二:
为什么不是0,2,4,6?
调用匿名函数传参是在for i in range(4)之后进行的,并且在匿名函数的域中找不到i,才到外层找的i,这时的i已经是循环4次之后的i,就也是3。所以最后打印的全是6 6 6 6.
如果你还是不能很好的理解那么我可以把他改成一般形式,让你更好的理解!
代码示例:

def func():
    list = []
    for i in range(4):
        def f(x):
            return i * x
        list.append(f)
    return list

for i in func():
    print(i(2),end=" ")
'''
运行结果:

6 6 6 6 
'''

可以为参数设置默认值解决这个问题:
代码示例:

def fun():
    temp = [lambda x,i=i:i*x for i in range(4)]
    return temp
for i in fun():
    print(i(2),end=" ")

'''
运行结果:

0 2 4 6 
'''

或许还有很多方法,就不一一列举了,主要理解什么是延迟绑定,并怎么预防他。

来一波,推送吧!
群号:781121386
群名:人生苦短,我学编程
欢迎大家加入我们,一起交流技术!!!

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值