在循环中将属性设置为类会覆盖最后的属性

时间:2016-12-07 19:14:00

标签: python

我正在尝试在运行时为类设置新属性并附加lambda,其行为取决于某些特定于属性的数据。如果我在循环中设置属性,就像在B类中一样,第一个属性会被覆盖。按顺序设置它们是有效的。找不到问题。在其他问题中提到我应该使用__getattr__而不是link中的属性。但我想了解这里的问题。

import time
class A():
    def __init__(self, dynprops = ['a', 'b']):

        setattr(A, 'a', property(lambda x: self.print_prop('a')))
        setattr(A, 'b', property(lambda x: self.print_prop('b')))

    def print_prop(self, dynprop):
        print(time.time(), dynprop)

class B():
    def __init__(self, dynprops = ['a', 'b']):

        for prop in dynprops:
            setattr(B, prop, property(lambda x: self.print_prop(prop)))

    def print_prop(self, dynprop):
        print(time.time(), dynprop)

a = A()
print(a.a)
print(a.b)
b = B()
print(b.a)
print(b.b)

给出

>> 1481137121.6755576 a
>> None
>> 1481137121.6756482 b
>> None
>> 1481137121.6757774 b
>> None
>> 1481137121.6758344 b
>> None

1 个答案:

答案 0 :(得分:3)

这是因为prop已更改为' b'然后保持这样。 lambda函数返回prop的当前值,而不是在lambda创建期间分配给它的值。要避免这种行为,您应该使用闭包:

class B():
    def __init__(self, dynprops = ['a', 'b']):
        for prop in dynprops:
            setattr(B, prop, property(self.printer(prop)))

    def print_prop(self, dynprop):
        print(time.time(), dynprop)

    def printer(self, prop):
        return lambda x: self.print_prop(prop)