python - 从属性列表动态创建属性到类

标签 python class

<分区>

我正在尝试为类动态创建一些方法,但是当我创建此类的对象并访问属性时,我总是得到最后一个值。

properties = ['a', 'b', 'c']
for p in properties:
    f = property(lambda self: p)
    print p # you see a, b, c
    print f # you can see it is 3 different objects
    setattr(MyClass, p, f)

obj = MyClass()
obj.a # returns c !!! why?
obj.b # returns c !!! why?
obj.c # returns c

更新

我能够使用创建方法的函数使其工作:

def create_function(p):    
    def f(self,):
        return p   
    return f

最佳答案

这与使用 property 无关。它在官方常见问题解答中解释为 Why do lambdas defined in a loop with different values all return the same result? .

当你这样做时:

properties = ['a', 'b', 'c']
for p in properties:
    f = property(lambda self: p)
    print p # you see a, b, c
    print f # you can see it is 3 different objects
    setattr(MyClass, p, f)

…每个f都是p变量的闭包。*这意味着,当你调用那个f时,它会返回p 在其定义范围内的当前值,而不是构造闭包时 p 的值。在循环结束时,p 的值为 'c',因此这是您所有属性的返回值。

您可以通过(在其他解决方案中**)使用“默认值 hack”来解决此问题:

properties = ['a', 'b', 'c']
for p in properties:
    f = property(lambda self, p=p: p)
    print p # you see a, b, c
    print f # you can see it is 3 different objects
    setattr(MyClass, p, f)

现在,每个属性都有一个名为p 的参数,其默认值为函数定义时p 的值。调用时(不提供 p 参数),主体以具有该值的局部变量 p 结束,而不是闭包变量 p指的是非本地范围。


* 实际上,它在技术上不是闭包,因为定义范围是全局的。但它的行为就像是在另一个范围内完成的一样。

** 还有一个 JavaScript 习惯用法,即创建一个新范围以在其中定义函数,(lambda p: lambda self: p)(p),或 functools.partial,或者创建一个可调用对象而不是一个函数,或者……但是,尽管名称中有“hack”这个词,“默认值 hack”是一个众所周知的 Python 习语,在文档中供奉并在stdlib,它通常是最佳答案,除非您有一些其他原因需要另一个范围或部分或自定义可调用。

关于python - 从属性列表动态创建属性到类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21270698/

相关文章:

javascript - MooTools 中的类转换?

来自 XML 的 C# 类定义

python - Pytest - 错误与失败

python - 一段时间后,pyglet 窗口会因 Schedule_once 挂起

java - 访问父类(super class)中方法的变量

python - 是否可以在 Python 中创建具有未知属性的类?

c++ - 如何在 C++ 中交叉包含类?

python - 我如何获得 Pandas 中一行的相等或最接近的值?

python - Pandas 滚动适用于允许nan

python - 在 iCal 中添加和删除数据