Python 如何在u_init中定义属性__

Python 如何在u_init中定义属性__,python,properties,constructor,Python,Properties,Constructor,我希望通过成员函数在类中定义属性。 下面是一些测试代码,显示了我希望它如何工作。然而,我没有得到预期的行为 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 al

我希望通过成员函数在类中定义属性。 下面是一些测试代码,显示了我希望它如何工作。然而,我没有得到预期的行为

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...> 
类篮(对象):
定义初始化(自):
#添加所有属性
对于self.PropNames()中的p:
setattr(self,p,property(lambda:p))
def PropNames(自身):
#所有属性的名称
return['Apple'、'Pear']
#正常性质
空气=财产(λs:“空气”)
如果名称=“\uuuuu main\uuuuuuuu”:
b=篮子()
打印b.空气#输出:“空气”
打印b.苹果#输出:
打印b.Pear#输出:

我如何才能让它工作?

您需要在类(即:
self.\uuuuu class\uuuuu
)上设置属性,而不是在对象(即:
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

的最后一个值满足您的要求:

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 

为什么要在
\uuuu init\uuuu
时间定义属性?这很令人困惑,也很聪明,所以你最好有一个很好的理由。Stef指出的循环问题只是应该避免这种情况的一个例子

如果您需要重新定义子类具有哪些属性,您可以在子类
\uuuu init\uuuu
方法中执行
del self.
,或者在子类中定义新属性

此外,还有一些风格上的挑剔:

  • 缩进到4个空格,而不是2个空格
  • 不要不必要地混合报价类型
  • 方法名称使用下划线而不是驼峰大小写<代码>道具名称->
    道具名称
  • PropNames
    实际上不需要是一种方法

我不同意正确的方法是元类。元类的功能太强大了,因为这可以用功能较弱的方法来实现。谢谢你的更新。实际上,在Python中,我从来没有像元类那样深入。也许这是一个开始阅读它们的好理由。主要原因是我可以从篮框中继承并重新定义道具名称。另外,原来的示例代码实际上缩进了4个空格,但当我将其复制到时,它丢失了缩进,所以我在2个空格上重新缩进。@pkit:编辑答案以讨论子类化。