2013-02-28 90 views
1

我想創建一個類級別的裝飾器,自動添加一個屬性到一個對象,包括適當的getter和setter方法和一個支持變量。例如:創建一個類級別的裝飾器,以自動添加一個屬性

@autoproperty("foo", can_get=True, can_set=True, allow_null=False, default_value=0) 
@autoproperty("baz", can_get=True, can_set=False, allow_null=True, default_value=0) 
@autoproperty("bar") 
class SomeNonTrivialClass(object): 
    def __init__(self): 
     #lots of stuff going on here 

    def discombobulate(self): 
     #this is obviously a very trivial example 
     local_foo = self.foo; 

     if (local_foo > 10): 
     raise RuntimeError("Foo can never be more than 10") 
     else: 
     #do whatever with foo 

if __name__ == '__main__': 
    test = SomeNonTrivialClass() 

    test.foo = 5 
    test.discombobulate() 
    test.foo = 11 
    test.discombobulate() 

我經常發現自己創建了大量的「半情結」 getter/setter方法的(他們可能只是一個簡單的屬性來完成,但他們需要的默認值和零保護,我想只是。能夠指定一個裝飾,做創建的類的新實例的屬性繁重。

如果我對這個做法大錯特錯,我打開一個同樣可行的方法。

任何幫助將不勝感激。

我正在使用python 3.X和python 2.7,所以在其中任何一個工作是首選但不是必要的。

更新:我添加了更多的品種,我在找什麼。一般來說,我需要能夠創建很多這些簡單的自動屬性(ala C#自動屬性,但具有更多的靈活性)。我不一定要公開後備存儲,但我確實希望確保對實例化對象(不一定是類)的檢查顯示已創建的屬性。

+0

聽起來你可能想寫一些[自定義描述符](http://me.veekun.com/blog/2012/05/23/python-faq-descriptors/)。 – Eevee 2013-02-28 19:17:26

+0

你的問題是什麼? – 2013-02-28 20:17:00

+0

@Robᵩ我的問題是如何創建一個類實例級別的裝飾器,它將自動在實例化類上創建正確的屬性。 – GrayWizardx 2013-02-28 23:12:47

回答

4

下面的類的裝飾會做到這一點:

def autoproperty(name, can_get=True, can_set=True, allow_null=False, default_value=0): 
    attribute_name = '_' + name 
    def getter(self): 
     return getattr(self, attribute_name, default_value) 
    def setter(self, value): 
     if not allow_null and value is None: 
      raise ValueError('Cannot set {} to None'.format(name)) 
     setattr(self, attribute_name, value) 

    prop = property(getter if can_get else None, setter if can_set else None) 

    def decorator(cls): 
     setattr(cls, name, prop) 
     return cls 

    return decorator 

,但你也可以同樣創建一個屬性工廠:

def autoproperty(attribute_name, can_get=True, can_set=True, allow_null=False, default_value=0): 
    def getter(self): 
     return getattr(self, attribute_name, default_value) 
    def setter(self, value): 
     if not allow_null and value is None: 
      raise ValueError('Cannot set {} to None'.format(name)) 
     setattr(self, attribute_name, value) 
    return property(getter if can_get else None, setter if can_set else None) 

然後設置與類:

class SomeNonTrivialClass(object): 
    # ... 

    foo = autoproperty('_foo', can_get=True, can_set=True, allow_null=False, default_value=0) 

類裝飾器w如果你需要創建多個屬性(或許有相互依賴關係),那麼應該更有意義。

+0

這正是我需要做的,我有一個類可能有一打需要配置的屬性。 – GrayWizardx 2013-02-28 23:06:48

+0

這工作非常接近我想要的。謝謝。 – GrayWizardx 2013-03-01 02:02:47

1

這是一個更直接的方法,它避免裝飾班級。

class SomeNonTrivialClass(object): 
    def __init__(self): 
     #lots of stuff going on here 

    foo = autoproperty("foo", can_get=True, can_set=True, allow_null=False, default_value=0) 

    def discombobulate(self): 
     #this is obviously a very trivial example 
     local_foo = self.foo; 

class autoproperty(property): 
    def __init__(self, name, can_get, can_set, allow_null, default_value): 
     ... 
+0

這對我來說似乎是一個NameError(因爲當您嘗試創建類時未定義自動屬性)。否則,據我所見,一個很好的建議... – mgilson 2013-02-28 19:05:37

+0

@mgilson:如果您在兩個類的主體之後創建實例,則爲NameError。 – cox 2013-02-28 19:18:07

+0

爲什麼我需要裝飾課堂的一部分是我不一定知道在設計時需要什麼屬性。它們是從一個原型工廠設施創建的,其後自動添加功能。 – GrayWizardx 2013-02-28 23:18:13

相關問題