2010-02-16 58 views
3

我有一個用C++編寫的大型庫,有人創建了一個接口,以自動方式在python(2.6)中使用它。現在我有很多使用getter和setter方法的類。真的:我討厭他們。從getter/setter自動轉換到屬性

我想使用屬性重新實現具有更多pythonic接口的類。問題是每個班級都有數以百計的getter和setter,而且我有很多班級。我如何自動創建屬性?

舉例來說,如果我有一個名爲MyClassGetX()SetX(x)GetYSetY,等等方法,類我如何可以自動創建一個派生類MyPythonicClass與物業X(可讀是否有吸氣如果存在setter,則是可寫的)等等?我希望有一種機制可以讓我選擇跳過一些getter/setter夫婦,這樣更好地完成手工工作。

回答

7

這裏是一種與類裝飾

def make_properties(c): 
    from collections import defaultdict 
    props=defaultdict(dict) 
    for k,v in vars(c).items(): 
     if k.startswith("Get"): 
      props[k[3:]]['getter']=v 
     if k.startswith("Set"): 
      props[k[3:]]['setter']=v 
    for k,v in props.items(): 
     setattr(c,k,property(v.get('getter'),v.get('setter'))) 
    return c 

@make_properties 
class C(object): 
    def GetX(self): 
     print "GetX" 
     return self._x 

    def SetX(self, value): 
     print "SetX" 
     self._x = value 

c=C() 
c.X=5 
c.X 

這裏有一個稍微更復雜的版本,它允許您指定的項目列表跳過

def make_properties(skip=None): 
    if skip is None: 
     skip=[] 
    def f(c): 
     from collections import defaultdict 
     props=defaultdict(dict) 
     for k,v in vars(c).items(): 
      if k.startswith("Get"): 
       props[k[3:]]['getter']=v 
      if k.startswith("Set"): 
       props[k[3:]]['setter']=v 
     for k,v in props.items(): 
      if k in skip: 
       continue 
      setattr(c,k,property(v.get('getter'),v.get('setter'))) 
     return c 
    return f 

@make_properties(skip=['Y']) 
class C(object): 
    def GetX(self): 
     print "GetX" 
     return self._x 

    def SetX(self, value): 
     print "SetX" 
     self._x = value 

    def GetY(self): 
     print "GetY" 
     return self._y 

    def SetY(self, value): 
     print "SetY" 
     self._y = value 

c=C() 
c.X=5 
c.X 
c.Y=5 
c.Y 
2

使用metaclass查找所有屬性,如Get*Set*,併爲該類添加適當的屬性。有一個可以設置爲包含將被跳過的屬性的序列的類屬性。有關設置班級屬性的詳細信息,請參閱this answer

+0

我不是很專業,你能給我一個例子來說明我的情況嗎? – 2010-02-16 22:33:02

+0

您不必爲此使用元類。這可能是更容易理解的代碼來定義'__getattr__'和'__setattr__'。你可以通過繼承將它們帶入你的課堂。 – 2010-02-16 23:35:28

1

小心使用魔法做特別是神奇地改變了其他人的約束力。這有以下缺點:

  • 您的代碼與訪問相同庫的其他人不兼容。有人無法導入您的某個模塊,或者複製並粘貼您的代碼,並使其與訪問相同庫的程序完美協作,並且您的接口與C++代碼的接口有所不同。如果你的包裝給你一個更好的,更高層次的接口,這是有道理的,但你的改變只是微不足道的。

考慮一下,如果處理所使用的庫是否更有意義。

+0

你是對的,但這不是一個很大的問題,我沒有爲其他人開發,我創建了這個接口,因爲我不喜歡getter/setter接口(也用C++)。我的接口擴展了舊接口,它不是替代,getter/setter方法仍然存在。 – 2010-02-17 07:46:40

1
class BaseObj: 
    test = None 
    def __init__(self, attributes_dict): 
     self.attributes_dict = attributes_dict 
     self.define_getters(attributes_dict.keys()) 
    def define_getters(self, attributes_names): 
     for attribute_name in attributes_names: 
      setattr(self, "get_"+attribute_name, self.getter_factory(attribute_name)) 
    def getter_factory(self, attribute_name): 
     """Method for generating getter functions""" 
     def getter(): 
      return self.attributes_dict[attribute_name] 
     return getter 

class DerivedObj(BaseObj): 
    attributes_keys = ['name'] 
    def __init__(self, attributes_dict): 
     BaseObj.__init__(self, attributes_dict) 

a = DerivedObj({'name':'kuku'}) 
a.get_name() # -> kuku 
+0

你可以添加一些關於這段代碼如何工作的解釋嗎? – fvrghl 2013-10-07 15:43:42