如何通过循环创建新的Python方法?(尝试将导致所有方法与最后定义的方法相同)
我正在研究从数据动态生成Python类。 (目的是让用户在不了解任何Python的情况下,在一个简单的文件中指定一些软件测试)。 我遇到了意想不到的效果; 作为一个玩具示例,为了快速检查我是否可以根据命名方案创建方法,我执行了以下操作:如何通过循环创建新的Python方法?(尝试将导致所有方法与最后定义的方法相同),python,types,lambda,metaprogramming,Python,Types,Lambda,Metaprogramming,我正在研究从数据动态生成Python类。 (目的是让用户在不了解任何Python的情况下,在一个简单的文件中指定一些软件测试)。 我遇到了意想不到的效果; 作为一个玩具示例,为了快速检查我是否可以根据命名方案创建方法,我执行了以下操作: import unittest attrdict = {} for i in range(3): attrdict["test%s"%i]= types.MethodType(lambda self: i) attrdict["runTest"]=la
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程序员来说,这可能是一个常见的“陷阱”,但我能想到的所有描述这个问题的术语都非常通用,以至于我的搜索只会返回大量不相关的答案
请你向我解释一下这里发生了什么,而不是我所期望的,最好是我应该做些什么来创造几种不同方法所期望的效果。问题在于这一行
attrdict["test%s"%i]= types.MethodType(lambda self: i)
当您定义一个引用非其参数的变量的
lambda
时,该变量将从实际调用时定义lambda
的范围中解析,因此您将始终得到i
的当前值,而不是定义lambda
时的i
值
在您的情况下,i
的值将在范围(3)中的for i循环完成后结束为2
,因此您需要创建一个闭包,以便在创建lambda
时将i
绑定到特定值,方法是将行更改为
attrdict["test%s"%i]= types.MethodType(lambda self, i=i: i)
当lambda被调用时,变量将从调用范围解析为“Not true”。调用它的作用域可能没有变量i
,或者可能有不同的变量。相反,它总是引用原始范围中的变量。这让我对发生了什么以及有效搜索更多内容的术语有了很好的了解。谢谢大家!@这是一个很好的观点。更新了答案。对types.MethodType(…)的调用实际上不是初始测试的一部分,而且目前为止,该调用缺少参数。很抱歉我粘贴了一个与预期略有不同的工作流阶段。因为答案中已经引用了它,并且没有伤害问题的要点,所以我将保持原样。