最近我开始玩Python,我遇到了一些特殊的闭包方式.请考虑以下代码:
adders=[0,1,2,3]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
Run Code Online (Sandbox Code Playgroud)
它构建了一个简单的函数数组,它接受单个输入并返回由数字添加的输入.函数在for循环中构造,迭代器i从中循环0到3.对于这些数字中的每一个,lambda都会创建一个函数i,该函数捕获并将其添加到函数的输入中.最后一行将第二个lambda函数3作为参数调用.令我惊讶的是输出结果是6.
我期待一个4.我的理由是:在Python中,一切都是一个对象,因此每个变量都是指向它的指针.在创建lambda闭包时i,我希望它存储一个指向当前指向的整数对象的指针i.这意味着当i分配一个新的整数对象时,它不应该影响先前创建的闭包.遗憾的是,adders在调试器中检查数组表明它确实存在.所有的lambda功能指的最后一个值i,3,这将导致adders[1](3)返回6.
这让我想知道以下内容:
lambda函数以更改其值i时不会受到影响的方式捕获当前i值?好吧,请耐心等待我,我知道这看起来会非常令人费解,但请帮助我了解发生了什么.
from functools import partial
class Cage(object):
def __init__(self, animal):
self.animal = animal
def gotimes(do_the_petting):
do_the_petting()
def get_petters():
for animal in ['cow', 'dog', 'cat']:
cage = Cage(animal)
def pet_function():
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, pet_function))
funs = list(get_petters())
for name, f in funs:
print name + ":",
f()
Run Code Online (Sandbox Code Playgroud)
得到:
cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.
Run Code Online (Sandbox Code Playgroud)
所以基本上,为什么我没有得到三种不同的动物?是不是cage'打包'进入嵌套函数的局部范围?如果没有,对嵌套函数的调用如何查找局部变量?
我知道遇到这些问题通常意味着一个人"做错了",但我想了解会发生什么.
我需要一个回调函数,对于一系列gui事件几乎完全相同.该函数的行为会略有不同,具体取决于调用它的事件.对我来说似乎是一个简单的案例,但我无法弄清楚lambda函数的这种奇怪的行为.
所以我在下面有以下简化代码:
def callback(msg):
print msg
#creating a list of function handles with an iterator
funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(lambda: callback(m))
for f in funcList:
f()
#create one at a time
funcList=[]
funcList.append(lambda: callback('do'))
funcList.append(lambda: callback('re'))
funcList.append(lambda: callback('mi'))
for f in funcList:
f()
Run Code Online (Sandbox Code Playgroud)
此代码的输出是:
mi
mi
mi
do
re
mi
Run Code Online (Sandbox Code Playgroud)
我期望:
do
re
mi
do
re
mi
Run Code Online (Sandbox Code Playgroud)
为什么使用迭代器搞砸了?
我尝试过使用深度镜:
import copy
funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(lambda: callback(copy.deepcopy(m)))
for f in funcList:
f()
Run Code Online (Sandbox Code Playgroud)
但这也存在同样的问题.
以下代码吐出1两次,我期望看到0然后1
def pv(v) :
print v
def test() :
value = []
value.append(0)
value.append(1)
x=[]
for v in value :
x.append(lambda : pv(v))
return x
x = test()
for xx in x:
xx()
Run Code Online (Sandbox Code Playgroud)
我希望python lambdas绑定到一个局部变量指向的引用,在场景后面.然而,情况似乎并非如此.我已经在一个大型系统中遇到了这个问题,其中lambda正在做现代C++的一个绑定的等价物(例如'boost :: bind'),在这种情况下,你将绑定到智能ptr或复制contstruct lambda的副本.
那么,如何将局部变量绑定到lambda函数并在使用时保留正确的引用?我对这种行为非常惊讶,因为我不希望这种语言来自垃圾收集器.
有问题的代码如下所示(l3_e是导致问题的变量):
for category in cat :
for l2 in cat[category].entries :
for l3 in cat[category].entries[l2].entry["sub_entries"] :
l3_e = cat[category].entries[l2].entry["sub_entries"][l3]
url = "http://forums.heroesofnewerth.com/" + l3_e.entry["url"]
self.l4_processing_status[l3_e] = 0
l3_discovery_requests.append( Request(
url, callback = lambda response : self.parse_l4(response,l3_e))) …Run Code Online (Sandbox Code Playgroud) 我需要在运行时为方法生成代码.能够运行任意代码并拥有文档字符串非常重要.
我想出了一个解决方案相结合exec,并setattr,这里是一个虚拟的例子:
class Viking(object):
def __init__(self):
code = '''
def dynamo(self, arg):
""" dynamo's a dynamic method!
"""
self.weight += 1
return arg * self.weight
'''
self.weight = 50
d = {}
exec code.strip() in d
setattr(self.__class__, 'dynamo', d['dynamo'])
if __name__ == "__main__":
v = Viking()
print v.dynamo(10)
print v.dynamo(10)
print v.dynamo.__doc__
Run Code Online (Sandbox Code Playgroud)
是否有更好/更安全/更惯用的方式来实现相同的结果?
如果我制作两个函数列表:
def makeFun(i):
return lambda: i
a = [makeFun(i) for i in range(10)]
b = [lambda: i for i in range(10)]
Run Code Online (Sandbox Code Playgroud)
为什么名单a和b不相等?
例如:
>>> a[2]()
2
>>> b[2]()
9
Run Code Online (Sandbox Code Playgroud) 正如可以使用type(name,base-classes,namespace-dict)创建动态类一样,是否可以创建动态函数?
我尝试过以下方面的做法:
>>> f = type("f", (function,), {})
NameError: name 'function' is not defined
Run Code Online (Sandbox Code Playgroud)
好的,所以我会很聪明,但是:
>>> def fn():
... pass
...
>>> type(fn)
<type 'function'>
>>> f = type("f", (type(fn),), {})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'function' is not an acceptable base type
Run Code Online (Sandbox Code Playgroud)
Python是否以与允许动态类相同的方式专门阻止动态函数的创建?
编辑:注意,我不允许任何使用exec ..因为我的问题是Python语言本身允许这样做.
提前致谢.
我有一个列表和一个lambda定义为的函数
In [1]: i = lambda x: a[x]
In [2]: alist = [(1, 2), (3, 4)]
Run Code Online (Sandbox Code Playgroud)
然后我尝试两种不同的方法来计算一个简单的总和
第一种方法.
In [3]: [i(0) + i(1) for a in alist]
Out[3]: [3, 7]
Run Code Online (Sandbox Code Playgroud)
第二种方法.
In [4]: list(i(0) + i(1) for a in alist)
Out[4]: [7, 7]
Run Code Online (Sandbox Code Playgroud)
两种结果都出乎意料地不同.为什么会这样?
我有一个我要按顺序评估的lambda函数列表.我不确定为什么,但只评估最后一个函数.示例如下:
>>> def f(x,z):
... print "x=",x,", z=",z
...
>>>
>>> g = lambda x : f(x,13)
>>> g(2)
x= 2 , z= 13 # As expected
>>>
>>> lst=[]
>>>
>>> for i in range(0,5):
... lst.append(lambda x: f(x,i))
...
>>> print lst
[<function <lambda> at 0x10341e2a8>, <function <lambda> at 0x10341e398>, <function <lambda> at 0x10341e410>, <function <lambda> at 0x10341e488>, <function <lambda> at 0x10341e500>]
>>>
>>> for fn in lst:
... fn(3)
...
x= 3 , z= 4 # z …Run Code Online (Sandbox Code Playgroud)