我想从成员函数中定义类中的属性。 下面是一些测试代码,显示了我希望如何工作。但是我没有得到预期的行为。
class Basket(object):
def __init__(self):
# add all the properties
for p in self.PropNames():
setattr(self, p, property(lambda : p) )
def PropNames(self):
# The names of all the properties
return ['Apple', 'Pear']
# normal property
Air = property(lambda s : "Air")
if __name__ == "__main__":
b = Basket()
print b.Air # outputs: "Air"
print b.Apple # outputs: <property object at 0x...>
print b.Pear # outputs: <property object at 0x...>
我怎么能让这个工作?
答案 0 :(得分:12)
您需要在类上设置属性(即:self.__class__
),而不是在对象上(即:self
)。例如:
class Basket(object):
def __init__(self):
# add all the properties
setattr(self.__class__, 'Apple', property(lambda s : 'Apple') )
setattr(self.__class__, 'Pear', property(lambda s : 'Pear') )
# normal property
Air = property(lambda s : "Air")
if __name__ == "__main__":
b = Basket()
print b.Air # outputs: "Air"
print b.Apple # outputs: "Apple"
print b.Pear # outputs: "Pear"
对于它的价值,在循环中创建lamdas时使用p
并不会给出您期望的行为。由于p
的值在循环中被更改,因此循环中设置的两个属性都返回相同的值:p
的最后一个值。
答案 1 :(得分:3)
这就是你想要的:
class Basket(object):
def __init__(self):
# add all the properties
def make_prop( name ):
def getter( self ):
return "I'm a " + name
return property(getter)
for p in self.PropNames():
setattr(Basket, p, make_prop(p) )
def PropNames(self):
# The names of all the properties
return ['Apple', 'Pear', 'Bread']
# normal property
Air = property(lambda s : "I'm Air")
if __name__ == "__main__":
b = Basket()
print b.Air
print b.Apple
print b.Pear
另一种方法是做一个元类......但是它们让很多人感到困惑^^。
因为我很无聊:
class WithProperties(type):
""" Converts `__props__` names to actual properties """
def __new__(cls, name, bases, attrs):
props = set( attrs.get('__props__', () ) )
for base in bases:
props |= set( getattr( base, '__props__', () ) )
def make_prop( name ):
def getter( self ):
return "I'm a " + name
return property( getter )
for prop in props:
attrs[ prop ] = make_prop( prop )
return super(WithProperties, cls).__new__(cls, name, bases, attrs)
class Basket(object):
__metaclass__ = WithProperties
__props__ = ['Apple', 'Pear']
Air = property(lambda s : "I'm Air")
class OtherBasket(Basket):
__props__ = ['Fish', 'Bread']
if __name__ == "__main__":
b = Basket()
print b.Air
print b.Apple
print b.Pear
c = OtherBasket()
print c.Air
print c.Apple
print c.Pear
print c.Fish
print c.Bread
答案 2 :(得分:0)
为什么要在__init__
时定义属性?它令人困惑和聪明,所以你最好有一个很好的理由。 Stef指出的循环问题只是为什么应该避免这种情况的一个例子。
如果需要重新定义子类具有哪些属性,则可以在子类del self.<property name>
方法中执行__init__
,或在子类中定义新属性。
另外,一些风格的挑剔:
PropNames
- &gt; prop_names
PropNames
并不一定是一种方法