【问题标题】:Python for loop initialization of reference to functionPython for循环初始化对函数的引用
【发布时间】:2015-04-21 16:11:51
【问题描述】:

我有这个示例代码,我希望它打印当前的 test.x 变量,但是当我使用 for 循环来定义函数引用列表时,我没有得到我期望的结果([1,1]和 [0,0])。当我改用注释行([0,1] 和 [1,0])时,我确实得到了我所期望的。我意识到有更简单的方法可以做到这一点,但对于我的程序,我需要它是这样的,但我想在 for 循环中定义规则对象,而不是在一行上定义每个元素,因为我不知道如何规则对象将很大。感谢您的帮助(Python 2.7)

class TestClass:
    def __init__(self):
        self.x = list([0, 1])
    def get_value(self, i):
        return self.x[i]

test = TestClass()
rules = list([None, None])
for a in range(2):
    rules[a] = lambda t: test.get_value(a)
#rules[0] = lambda t: test.get_value(0)
#rules[1] = lambda t: test.get_value(1)

print(rules[0](0), rules[1](0))
test.x[0] = 1
test.x[1] = 0
print(rules[0](0), rules[1](0))

【问题讨论】:

  • 你为什么要copy.copy一个0和一个1?
  • 我认为问题是 rules[0] 和 rules[1] 都在调用 test.get_value(1) 我认为 copy.copy 可能会有所帮助,但它不是
  • 您标记了问题 python 2.7,但您的代码似乎是 python 3

标签: python python-2.7


【解决方案1】:

这个问题可以更简洁地表示如下:

>>> rules = list([None, None])
>>> for a in range(2):
...   rules[a] = lambda t: a
... 
>>> rules[0](0)
1
>>> rules[0](1)
1
>>> rules[1](0)
1
>>> rules[1](1)
1

我认为问题在于代码总是反映a的最终值。

这称为“后期绑定闭包”,在 Python Guide here 中进行了讨论。

解决这个问题的一种(相当难看的)方法是每次通过使用functools 包部分应用函数来创建新函数。这会“捕获”a 的当前值。

>>> from functools import partial
>>> for a in range(2):
...   def get(t,x): return x
...   rules[a] = partial(get,x=a)
... 
>>> rules[0](0)
0
>>> rules[0](1)
0
>>> rules[1](0)
1
>>> rules[1](1)
1

实现相同效果的更简单方法:

>>> for a in range(2):
...   rules[a] = lambda t,a=a: a

如链接的 Python 指南中所示,您还可以使用列表推导来稍微简化代码:

rules = [lambda t,a=a: a for a in range(2)]

【讨论】:

  • 谢谢,这行得通。虽然它可以用 partial(lambda t, x: x, x=a) 来简化
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-03
相关资源
最近更新 更多