问题是tests
中的每个函数都指的是变量i
。
更常见的是,您可以在函数内部执行此操作,在这种情况下,您有一个局部定义范围的变量i
,它将存储在闭包中,在These Nasty Closures中有很好的解释。
但是这里更简单:i
是一个全局变量,所以没有关闭。编译这些函数以在运行时查找i
作为全局变量。由于i
已更改,所以函数在运行时将看到更改的值。就那么简单。
解决这个问题的传统方式(这同时适用于封闭和全局变量)被亲切地称为“默认值黑客”,即使它不是一个真正的黑客。 (见the explanation in the FAQ。)瑞安海宁的回答解释了如何做到这一点:
lambda x, i=i: x%i==0
这将创建一个名为i
参数,等于在创建函数时的i
值的默认值。然后,在函数内部,当您访问参数i
时,您将获得该值。
一种不同的方式解决这个问题,如果您使用的是像JavaScript语言可能看起来比较熟悉,是创建一个函数创建功能,并传递的i
值作为参数传递给该功能 - 创建功能,如user2864740的回答是:
(lambda i: lambda x: x%i)(i)
这避免“污染”功能的签名与一个额外的参数(有人可能会不小心将参数传递到),但在创建和调用函数的成本没有很好的理由。
解决此第三种方法是使用partial
。如果您所要做的只是部分应用功能,则使用partial
而不是定义包装函数,因为lambda
可能更清晰。
不幸的是,在这种情况下,函数隐藏在一个运算符中,并且函数operator.mod
公开它并不带关键字参数,所以你不能有用地部分分配它的第二个操作数。所以,在这种情况下这是一个不好的解决方案。如果你真的想,你可以只写一个表现更好的包装和partial
是:
def opmod(a, b):
return a % b
partial(operator.mod, b=i)
在这种情况下,我认为你是与其他解决方案更好;只要保留这个在你的脑袋是适当的情况下。
另请参阅[这些讨厌的闭包](http://code.activestate.com/recipes/502271/)比在官方文档中更好的解释。但简短的版本是,这些测试函数中的每一个实际上都是围绕同一个变量'i'的闭包,而'i'保持不断变化的值。 (这是不准确的,因为全局变量实际上并不需要存储在闭包中,但效果是一样的。) – abarnert