python 中的工厂函数,简单理解就是:高阶函数的一种,可以返回函数的函数。
一般我们可以写出这样的工厂函数:
def func(x):
return lambda: x
然后验证一下:
print(func(2)())
# 2
输出为2。没错,就是我们期待的结果。
然后,再来一个带循环体的(错误的示范!):
def multi(x):
ret = []
for ele in range(x):
ret.append(lambda: ele)
return ret
- 输出验证一下:
for action in multi(5):
print(action(),end="\t")
# 4 4 4 4 4
这时候就出问题了。lambda 并没有记住我们所期待的
ele而是记住了最后一个ele.
- 如何解决?
- 全部设置默认参数就好了。
那么修改后的代码如下(正确的示范):
def multi(x):
ret = []
for ele in range(x):
ret.append(lambda k=ele: k)
return ret
- 输出如下
for action in multi(5):
print(action(), end="\t")
# 0 1 2 3 4
对于之前的func()函数呢?当然也可以设置默认参数:
def func(x):
return lambda p=x: p
通过对默认参数的设置,代码就不会依赖运行时的检查,而是在定义时就明确知道状态信息。
- 分析:为何定义了默认参数值,就可以避免循环中出现的问题?
以multi(x)函数为例:其等价形式为:
def multi(x):
ret = []
for ele in range(x):
def temp(t=ele):
return t
ret.append(temp)
return ret
- 在
def multi(x):中,变量ele和函数temp()是同时被创建的。都是在multi(x)函数被调用时创建。 - 而
def temp():中的返回值t是在temp()函数被调用的时候创建。 - 而且这两个函数总是不能同时被调用。总是需要
multi(x)()这样的方式去调用。也就导致了t总是在ele创建之后被创建。 - 所以在这样的场景下,如果不设置默认值,
t返回的总是最后一个ele的值。 - 而,如果给
temp()函数设置了默认参数temp(t=ele),就强制在temp()函数被创建的时候,就创建变量t.这样刚好就达到了预期:在遍历的过程中,不断地去改变ele的值,同时t也随着ele的改变而改变。(如果不做这种默认参数的设置。对t的赋值实际上只发生了一次,也就是在temp()被调用的时候发生了一次。)
总结:
x,ret,ele都是在multi(x)被调用的时候创建的temp()的返回值,是在temp()被调用的时候创建的temp()总是在multi(x)被调用之后才调用- 要想让
temp()得到遍历中的每次ele的值,就可以通过默认参数的方式,让temp()在遍历的过程中就得到ele的值。(这也许是目前唯一的办法)
其实表述的不是很准确:python中所有对变量的赋值操作实质上都是对对象的引用的修改。
在上述行为中,也就是不断改变t的引用。t = ele = num(obj).ele每次引用不同的对象,而t总是做与ele相同的引用。
Python工厂函数详解

本文深入探讨了Python中工厂函数的概念及使用方法,并通过实例详细解释了如何利用默认参数解决循环体中lambda函数的问题。
3432

被折叠的 条评论
为什么被折叠?



