2010-02-16 35 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