Python中late-binding-closures
2018-01-03 @望京
示例1
>>> b = [] >>> for i in range(5): ... b.append(lambda :i) ... >>> for j in b: ... print j() ... 4 4 4 4 4 >>> for m in b: ... print type(m),m ... <type 'function'> <function <lambda> at 0x7fe4aae708c0> <type 'function'> <function <lambda> at 0x7fe4aae70938> <type 'function'> <function <lambda> at 0x7fe4aae709b0> <type 'function'> <function <lambda> at 0x7fe4aae70b18> <type 'function'> <function <lambda> at 0x7fe4aae70b90> >>> >>>
为什么不是输出 0~4?
Closures in Python are late-binding, meaning that each lambda function in the list will only evaluate the variable i when invoked, and not when defined. That's why all functions return the same value, i.e. the last value of ì (which is 4).
late-binding-closures in Python http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures
怎么修改使之输出 0~4? b.append(lambda i=i:i)
>>> b = [] >>> for i in range(5): ... b.append(lambda i=i:i) ... >>> for j in b: ... print j() ... 0 1 2 3 4 >>>
或者使用 functools.partial :
>>> b = [] >>> for i in range(5): ... from functools import partial ... b.append(partial(lambda x:x, i)) ... >>> for j in b: ... print j() ... 0 1 2 3 4 >>>
lambda补充
>>> foo = [2, 18, 9, 22, 17, 24, 8, 12, 27] >>> >>> print filter(lambda x: x % 3 == 0, foo) # 过滤 [18, 9, 24, 12, 27] >>> >>> print map(lambda x: x * 2 + 10, foo) # map [14, 46, 28, 54, 44, 58, 26, 34, 64] >>> >>> print reduce(lambda x, y: x + y, foo) # 求和 139 >>>
示例2
>>> def func(arg=[]): ... arg.append(1) ... print arg ... >>> func() [1] >>> func() [1, 1] >>>
修改1:在函数调用的时候传入参数
>>> def func(arg=[]): ... arg.append(1) ... print arg ... >>> func([]) [1] >>> func([]) [1] >>>
修改2:默认参数改为 None (更安全的做法)
>>> >>> def func(arg=None): ... if not arg: ... arg = [] ... arg.append(1) ... print arg ... >>> >>> func() [1] >>> func() [1] >>>
示例3
>>> >>> def func(x, l=[]): ... for i in range(x): ... l.append(i*i) ... print l ... >>> func(2) [0, 1] >>> func(3) [0, 1, 0, 1, 4] >>>
2018-03-12 https://zhuanlan.zhihu.com/p/33376761
今天在地铁上看到公众号推荐这个文章,也是late-binding问题,再补充下:
def foo(): temp = [lambda x : i*x for i in range(4)] return temp for bar in foo(): print(bar(2)) # 输出 6 6 6 6
其实可以改写成下面这样,这样就比较容易看出是闭包了:lambda本身是一个函数,调用了外面的变量 i
temp = [] for i in range(4): temp.append(lambda x : i*x) for bar in temp: print(bar(2))
解决方法1: [lambda x,i=i : i*x for i in range(4)]
def foo(): temp = [lambda x,i=i : i*x for i in range(4)] return temp for bar in foo(): print(bar(2))
解决方法2:使用 functools.partial
from functools import partial from operator import mul def foo(): temp = [partial(mul,i) for i in range(4)] return temp for bar in foo(): print(bar(2))
解决方法3:把temp改成生成器
def foo(): temp = (lambda x : i*x for i in range(4)) return temp for bar in foo(): print(bar(2)) # 或者用 next() 方式调用 # bar = foo() # print(next(bar)(2)) # print(next(bar)(2)) # print(next(bar)(2)) # print(next(bar)(2)) # 或者用 next() 方式调用 # bar = foo() # print(bar.__next__()(2)) # print(bar.__next__()(2)) # print(bar.__next__()(2)) # print(bar.__next__()(2))
解决方法4:使用yield
def foo(): for i in range(4): yield lambda x : i*x for bar in foo(): print(bar(2))
补充:
构造生成器的两种方式: 使用类似列表生成式的方式生成 (2*n + 1 for n in range(3, 11)) 使用包含yield的函数来生成 如果计算过程比较简单,可以直接把列表生成式改成generator; 但是,如果计算过程比较复杂,就只能通过包含yield的函数来构造generator。
学无止境,戒骄戒躁。
作者:Standby — 一生热爱名山大川、草原沙漠,还有我们小郭宝贝!
出处:http://www.cnblogs.com/standby/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://www.cnblogs.com/standby/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。