Python闭包的延迟绑定

Python闭包

1. 什么是闭包, 闭包必须满足以下3个条:
  • 必须是一个嵌套函数
  • 闭包必须返回嵌套的函数
  • 嵌套函数必须引用一个外部的非全局的变量
2. 闭包的优点
  • 避免使用全局变量
  • 可以提供部分数据的隐藏
  • 可以提供更优雅的面向对象实现
def Add(a):
	def add(b):
		return a + b
	return add
ad(2)(2)  # 计算2+2的值, 用类实现的话, 相对麻烦

# 闭包使用nonlocal
def tester(start):
    state = start
    def nested(label):
        nonlocal state
        print(label, state)
        state += 1
    return nested  # 结合nonlocal使用的话还能实现意想不到的效果, 初始情况下给start传入不同的值, 会保存到不同的对象

def test(start):
    global state
    state = start
    def nest(label):
        global state
        print(label, state)
        state += 1
    return nest  # global的话初始情况下给start无论传入什么值, 操作的始终都是一个对象, 达不到类实现的效果

# 类实现nonlocal的效果
class MyClass:
    def __init__(self, start):
        self.start = start

    def nest(self, label):
        print(label, self.start)
        self.start += 1
3. 闭包的延迟绑定
def multipliers():
	return [lambda x : i*x for i in range(4)]
print([m(2) for m in multipliers()])
# 打印结果是[6, 6, 6, 6], 而不是[0, 2, 4, 6]
# 原因: i不仅仅控制着循环次数, 而且还在为i*x的i提供引用的值, 当Python解释器运行的时候, 调用multipliers()的时候, 只会先定义lambda匿名函数, 但是却会直接运行后面的for循环, 当lambda被调用的时候, i已经指向了4, 这就是延迟绑定的特性(Python中非局部变量绑定的是内存地址, 局部变量绑定的是值)
4. 延迟绑定的解决办法

方法一:

def multipliers():
	return [lambda x, i=i: i*x for i in range(4)]
print([m(2) for m in multipliers()])
# 打印结果是[0, 2, 4, 6]
# Python解释器在定义函数时, 遇到关键字参数, 就必须初始化参数, 此时后面的for循环每循环一次, 前面的关键字参数i就需要找一次引用对象, for循环每循环一次结果i都会被i这个关键字参数指向, 这个指向的是值, 不是空间

方法二: Python生成器

def f1():
    for i in range(4): yield lambda x: x * i
print(list((m(2) for m in f1())))
# list()中是()这个是生成器的推导式(这种方法可以简单的调用上面的函数内部的生成器)
总结: 延迟绑定只是一种现象, 一种特征, 并不是本质
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值