簡體   English   中英

如何在__init__中定義屬性

[英]How to define properties in __init__

我想從成員函數中定義類中的屬性。 下面是一些測試代碼,顯示了我希望如何工作。 但是我沒有得到預期的行為。

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.__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的最后一個值。

這樣做你想要的:

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 

為什么要在__init__時定義屬性? 它令人困惑和聰明,所以你最好有一個很好的理由。 Stef指出的循環問題只是為什么應該避免的一個例子。

如果需要重新定義子類具有哪些屬性,則可以在子類__init__方法中執行del self.<property name> ,或在子類中定義新屬性。

還有,一些風格的挑剔:

  • 縮進到4個空格,而不是2個
  • 不要不必要地混合報價類型
  • 對於方法名稱,請使用下划線而不是駝峰大小寫。 PropNames - > prop_names
  • PropNames實際上不一定是一種方法

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM