2013-10-16 120 views
2

在一個類中,我想定義N個持久屬性。我可以實現它們如下:實現Python持久屬性

@property 
def prop1(self): 
    return self.__prop1 
@prop1.setter 
def prop1(self, value): 
    self.__prop1 = value 
    persistenceManagement()   

@property 
def prop2(self): 
    return self.__prop2 
@prop2.setter 
def prop2(self, value): 
    self.__prop2 = value 
    persistenceManagement()  

[...] 

@property 
def propN(self): 
    return self.__propN 
@propN.setter 
def propN(self, value): 
    self.__propN = value 
    persistenceManagement()  

當然,這些塊之間唯一不同的是屬性名稱(prop1,prop2,...,propN)。 persistenceManagement()是一個函數,當這些屬性的值發生更改時,必須調用它。

由於這些代碼塊除了一個單一的信息(即屬性名稱)是相同的,我想必須有某種方法來用單行代替每個這些塊,聲明存在一個持久屬性給定名稱。像

def someMagicalPatternFunction(...): 
    [...] 


someMagicalPatternFunction("prop1") 
someMagicalPatternFunction("prop2") 
[...] 
someMagicalPatternFunction("propN") 

...或者可能是一些裝飾技巧,我目前無法看到。有人有一個想法如何做到這一點?

+0

所以你想要做的只是在任何這些屬性設置後運行一個函數,對吧? – Blender

+0

@Blender好吧......讓setter和getter自動聲明+向setter添加一行代碼以實現持久性。 –

+0

@martineau我責備複製和粘貼。感謝您的注意。我編輯了這個問題。 –

回答

3

屬性只是descriptor類,你可以創建自己的,並使用它們:

class MyDescriptor(object): 
    def __init__(self, name, func): 
     self.func = func 
     self.attr_name = '__' + name 
    def __get__(self, instance, owner): 
     return getattr(self, self.attr_name) 
    def __set__(self, instance, value): 
     setattr(self, self.attr_name, value) 
     self.func(self.attr_name) 

def postprocess(attr_name): 
    print 'postprocess called after setting', attr_name 

class Example(object): 
    prop1 = MyDescriptor('prop1', postprocess) 
    prop2 = MyDescriptor('prop2', postprocess) 

obj = Example() 
obj.prop1 = 'answer' # prints 'postprocess called after setting __prop1' 
obj.prop2 = 42 # prints 'postprocess called after setting __prop2' 

可選你可以把它輕鬆一點的是這樣使用:

def my_property(name, postprocess=postprocess): 
    return MyDescriptor(name, postprocess) 

class Example(object): 
    prop1 = my_property('prop1') 
    prop2 = my_property('prop2') 

如果您像裝飾者@語法,你可以這樣做(這也減輕了不得不鍵入兩次財產的名稱) - 但它需要的虛擬功能似乎有點奇怪...

def my_property(method): 
    name = method.__name__ 
    return MyDescriptor(name, postprocess) 

class Example(object): 
    @my_property 
    def prop1(self): pass 
    @my_property 
    def prop2(self): pass 
+0

謝謝。非常有啓發性。 –