2012-04-13 71 views
13

TL; DR:必須爲每個屬性定義一組唯一的getter和setter()'d變量。我可以定義泛型getter和setter並將它們與我想要的任何變量一起使用嗎?Python:泛型getter和setter

比方說,我做了一些不錯的getter和setter類:

class Foo 
    def getter(self): 
     return _bar+' sasquatch' 

    def setter(self, value): 
     _bar = value+' unicorns' 

    bar = property(getter, setter) 

非常偉大的,對不對?

現在,讓我們說,我把另一個變量稱爲「baz」,我不希望它從這個sasquatch /獨角獸的樂趣中排除。嗯,我想我可以做另一套getter和setter:

class Foo 
    def bar_getter(self): 
     return _bar+' sasquatch' 

    def bar_setter(self, value): 
     _bar = value+' unicorns' 

    bar = property(bar_getter, bar_setter) 

    def baz_getter(self): 
     return _baz+' sasquatch' 

    def baz_setter(self, value): 
     _baz = value+' unicorns' 

    baz = property(baz_getter, baz_setter) 

但是,這不是很乾燥,不必要的雜波我的代碼。我想我可以讓它有點DRYer:

class Foo 
    def unicornify(self, value): 
     return value+' unicorns' 

    def sasquatchify(self, value): 
     return value+' sasquatch' 

    def bar_getter(self): 
     return self.sasquatchify(_bar) 

    def bar_setter(self, value): 
     _bar = self.unicornify(_bar) 

    bar = property(bar_getter, bar_setter) 

    def baz_getter(self): 
     return self.sasquatchify(_baz) 

    def baz_setter(self, value): 
     _baz = self.unicornify(_baz) 

    baz = property(baz_getter, baz_setter) 

雖然這可能會使我的代碼DRYer,它不是理想的。如果我想獨角獸和sasquatchify兩個更多的變量,我將不得不添加四個更多的功能!

必須有更好的方法來做到這一點。我可以在多個變量中使用單個通用getter和/或setter嗎?

獨角獸少和無sasquatch真實世界的實現:我使用SQLAlchemy ORM,並希望從數據庫存儲和檢索它時轉換某些數據。有些轉換適用於多個變量,我不想用getter和setter混淆我的類。

回答

12

如何只:

def sasquatchicorn(name): 
    return property(lambda self: getattr(self, name) + ' sasquatch', 
        lambda self, val: setattr(self, name, val + ' unicorns')) 

class Foo(object): 
    bar = sasquatchicorn('_bar') 
    baz = sasquatchicorn('_baz') 

有些更一般:

def sasquatchify(val): 
    return val + ' sasquatch' 

def unicornify(val): 
    return val + ' unicorns' 

def getset(name, getting, setting): 
    return property(lambda self: getting(getattr(self, name)), 
        lambda self, val: setattr(self, name, setting(val))) 

class Foo(object): 
    bar = getset('_bar', sasquatchify, unicornify) 
    baz = getset('_baz', sasquatchify, unicornify) 

或者勉強更多的工作,你可以使用完整的描述協議,在agf's answer描述。

+1

但lambda表達式限制getter和setter方法,以一個單一的表達,這是不適合我需要什麼做。 – 2012-04-13 23:17:17

+0

@TheronLuhn所以做同樣的事情,但與一般功能(或定義爲'sasquatchicorn'的內部函數或名稱作爲參數)。或者按照[agf](http://stackoverflow.com/a/10149431/344821)的答案做完整的描述符處理。 – Dougal 2012-04-13 23:22:19

+0

或者在我的編輯中做這件事,這可能比做一個完整的描述符稍微少一些。也許? :) – Dougal 2012-04-13 23:50:51

5

這就是descriptor protocolproperty是基於爲:

class Sasicorn(object):        
    def __init__(self, attr):       
     self.attr = "_" + attr      
    def __get__(self, obj, objtype):     
     return getattr(obj, self.attr) + ' sasquatch' 
    def __set__(self, obj, value):     
     setattr(obj, self.attr, value + ' unicorns') 

class Foo(object):         
    def __init__(self, value = "bar"):    
     self.bar = value        
     self.baz = "baz"        
    bar = Sasicorn('bar')        
    baz = Sasicorn('baz')        

foo = Foo()           
foo2 = Foo('other')         
print foo.bar           
# prints bar unicorns sasquatch 
print foo.baz           
# prints baz unicorns sasquatch 
print foo2.bar          
# prints other unicorns sasquatch 

雖然在工廠的功能可以爲你的玩具例如被罰款property,聽起來也許您需要爲您的實際使用情況的更多控制。

+0

我一直在爲此苦苦掙扎,而且我可能錯了,但看起來這實際上會定義類的所有實例之間共享的類級「屬性」。這個答案很有幫助,但是這種行爲對我來說當然不是。 – krs013 2016-06-09 05:45:43

+1

@ krs013你說得對,雖然它顯示了描述符協議,但它並不是非常有用。我已經更新它將值存儲在實例上而不是類中。 – agf 2016-06-09 10:16:26

+0

謝謝,這是我一直在尋找的行爲。在其他地方,我曾看到描述符直接訪問對象的__dict__,但我認爲這看起來更清晰。 – krs013 2016-06-09 14:39:21

1

我的一位同事建議使用閉包來返回getter和setter函數,這是我決定使用的。

class Foo(object): 
    def setter(var): 
     def set(self, value): 
      setattr(self, var, value+' unicorn') 
     return set 

    def getter(var): 
     def get(self): 
      return getattr(self, var)+' sasquatch' 
     return get 

    bar = property(getter('_bar'), setter('_bar')) 

f = Foo() 
f.foo = 'hi' 
print f.foo 

但還是非常感謝大家對你的答案:)

+1

這與Dougal的答案基本相同,但使用函數而不是lambda表達式。 – Darthfett 2012-04-17 19:43:35

+0

是嗎?對不起,我是Python新手。我會接受Dougal的。 – 2012-04-17 19:51:17

1

使用getattributesetattr你可以定義這個對所有屬性的過去和未來。

class Foo(object):                               

    x = 3 

    def __getattribute__(self, attr): 
    return str(object.__getattribute__(self, attr)) + ' sasquatch' 

    def __setattr__(self, attr, value): 
    object.__setattr__(self, attr, str(value) + ' unicorn') 

print Foo.x 
f = Foo() 
print f.x 
f.y = 4 
print f.y 

此打印:

3 
3 sasquatch 
4 unicorn sasquatch 
-1
# coding=utf-8 
__author__ = 'Ahmed Şeref GÜNEYSU' 


class Student(object): 
    def __init__(self, **kwargs): 
     for k, v in kwargs.iteritems(): 
      self.__setattr__(k, v) 

if __name__ == '__main__': 
    o = Student(first_name='Ahmed Şeref', last_name='GÜNEYSU') 
    print "{0} {1}".format(o.first_name, o.last_name) 
    print o.email 

給人

Ahmed Şeref GÜNEYSU 
    File "/Users/ahmed/PycharmProjects/sanbox/abstract_classes/object_initializer/__init__.py", line 13, in <module> 
    print o.email 
AttributeError: 'Student' object has no attribute 'email' 

Process finished with exit code 137