python 进阶之路:绑定延迟

看看下面一题,试着写出自己的答案。
def multipliers():
    return [lambda x: i * x for i in range(4)]


print([m(2) for m in multipliers()])
print(type(multipliers()))


res:

[6, 6, 6, 6]
<class 'list'>

输出结果不是我们想的[0,2,4,6],这是为什么呢?如何输出我们想的结果呢?

首先,上述问题产生的原因是python 闭包的延迟绑定。在这里你可能会有疑问
,什么是闭包?
在python 的核心编程里,闭包定义如下:
如果在一个内部函数里,对外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被
认定为闭包。
总结为三点:
1、是一个内嵌函数
2、对外部函数变量的引用
3、外部函数返回内嵌函数
简单的闭包eg:
def counter(start_at=0):
    count = [start_at]
    def incr():
        count[0] += 1
        return count[0]
    return incr

继续刚才的问题,python 闭包的延迟绑定,意味着
内部函数被调用,时,参数的值在闭包内进行查找。因此,
当任何有multipliers()返回的函数被调用时,i 的值
将在附近范围进行查找。那是不管返回函数是否被调用,for
循环已经完成,i被赋予最终值3,因此,每次返回的函数乘以
传递过来的值3 ,因为上段代码传过来的值是2,他们最终的返回都是6。


以匿名函数的形式,看着你可能存在疑惑,现在为你转换成 for循环语句,
便于你理解。

def func():
    fun_list = []
    for i in range(4):
        def foo(x):
            return x*i
        fun_list.append(foo)
    return fun_list
for m in func():
  print m(2)




那现在考虑一下,如何输出我们想的结果【0,2,4,6】?
两种方法为您推荐:
方法一:
def multipliers():
    for i in range(4): yield lambda x: i * x
print([m(2) for m in multipliers()])
print(type(multipliers()))

res:
    [0, 2, 4, 6]
    <class 'generator'>

方法二:

def multipliers():
    return [lambda x, i=i: i * x for i in range(4)]


print([m(2) for m in multipliers()])
print(type(multipliers()))


res:

    [0, 2, 4, 6]
    <class 'list'>

 

posted @ 2021-01-21 11:27  青春叛逆者  阅读(107)  评论(0编辑  收藏  举报