相关疑难解决方法(0)

(lambda)函数闭包捕获了什么?

最近我开始玩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从中循环03.对于这些数字中的每一个,lambda都会创建一个函数i,该函数捕获并将其添加到函数的输入中.最后一行将第二个lambda函数3作为参数调用.令我惊讶的是输出结果是6.

我期待一个4.我的理由是:在Python中,一切都是一个对象,因此每个变量都是指向它的指针.在创建lambda闭包时i,我希望它存储一个指向当前指向的整数对象的指针i.这意味着当i分配一个新的整数对象时,它不应该影响先前创建的闭包.遗憾的是,adders在调试器中检查数组表明它确实存在.所有的lambda功能指的最后一个值i,3,这将导致adders[1](3)返回6.

这让我想知道以下内容:

  • 闭包捕获的内容是什么?
  • 什么是最优雅的方式来说服lambda函数以更改其值i时不会受到影响的方式捕获当前i值?

python lambda closures

237
推荐指数
5
解决办法
4万
查看次数

嵌套函数中的局部变量

好吧,请耐心等待我,我知道这看起来会非常令人费解,但请帮助我了解发生了什么.

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'打包'进入嵌套函数的局部范围?如果没有,对嵌套函数的调用如何查找局部变量?

我知道遇到这些问题通常意味着一个人"做错了",但我想了解会发生什么.

python closures scope nested-function

102
推荐指数
3
解决办法
9449
查看次数

lambda函数的范围及其参数?

我需要一个回调函数,对于一系列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)

但这也存在同样的问题.

python lexical-closures

79
推荐指数
3
解决办法
3万
查看次数

76
推荐指数
4
解决办法
9万
查看次数

Python lambda绑定到本地值

以下代码吐出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)

python lambda closures

59
推荐指数
2
解决办法
2万
查看次数

Python中的动态/运行时方法创建(代码生成)

我需要在运行时为方法生成代码.能够运行任意代码并拥有文档字符串非常重要.

我想出了一个解决方案相结合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)

是否有更好/更安全/更惯用的方式来实现相同的结果?

python metaprogramming exec

42
推荐指数
3
解决办法
4万
查看次数

使用python中的lambda表达式在循环内生成函数

如果我制作两个函数列表:

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)

为什么名单ab不相等?

例如:

>>> a[2]()
2
>>> b[2]()
9
Run Code Online (Sandbox Code Playgroud)

python lambda scope

29
推荐指数
3
解决办法
8761
查看次数

Python中可以使用真正的动态和匿名函数吗?

正如可以使用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语言本身允许这样做.

提前致谢.

python

24
推荐指数
3
解决办法
2万
查看次数

列表(生成器)的意外输出

我有一个列表和一个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)

两种结果都出乎意料地不同.为什么会这样?

python list-comprehension generator-expression python-2.7

20
推荐指数
3
解决办法
4555
查看次数

评估python lambda函数列表仅评估最后一个列表元素

我有一个我要按顺序评估的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)

python

13
推荐指数
1
解决办法
5679
查看次数