0

我正在研究从数据动态生成 Python 类。(目的是让用户在一个简单的文件中指定一些软件测试,而无需了解任何 Python)。我遇到了我没想到的效果;作为一个快速检查我是否可以根据命名方案创建方法的玩具示例,我执行了以下操作:

import unittest

attrdict = {}
for i in range(3):
    attrdict["test%s"%i]= types.MethodType(lambda self: i)
attrdict["runTest"]=lambda self: [eval("self.test%s()"%i) for i in range(3)]
dynTC = type('dynTC', (unittest.TestCase,), attrdict )

现在当我执行

dynTC().runTest()

...我希望

[0,1,2] 

作为输出,但实际结果是

[2,2,2]

我希望 lambda 定义绑定循环索引的深层副本,因为它只是一个数字而不是更复杂的结构,但显然这里发生了一些我不明白的事情。

我有一种感觉,对于新的 Python 程序员来说,这可能是一个常见的“陷阱”,但是我能想到的描述问题的所有术语都非常笼统,以至于我的搜索只返回了大量不相关的答案。

您能否向我解释一下这里发生了什么而不是我的预期,最好还解释一下我应该做些什么来创建几种/不同/方法的预期效果。

4

1 回答 1

1

问题出在这条线...

attrdict["test%s"%i]= types.MethodType(lambda self: i)

当您定义一个lambda引用不是其参数之一的变量的 a 时,该变量将从lambda实际调用时定义的范围解析,因此您将始终获得的当前值i是,而不是i定义 时的值lambda

在您的情况下,值i2for i in range(3)循环完成后结束,因此您需要在创建时创建一个闭包以绑定i到特定值lambda,方法是将行更改为...

attrdict["test%s"%i]= types.MethodType(lambda self, i=i: i)
于 2013-06-27T13:07:11.267 回答