我有一个用C ++编写的大型库,有人创建了一个以自动方式在python(2.6)中使用它的接口。现在我有很多带有getter和setter方法的类。真的:我恨他们。
我想使用属性重新实现具有更多pythonic接口的类。问题是每个班级都有数百个getter和setter,而且我有很多课程。如何自动创建属性?
例如,如果我有一个名为MyClass
的课程,其中包含GetX()
和SetX(x)
,GetY
,SetY
等方法,我可以使用属性MyPythonicClass
自动创建派生类X
(如果有getter则可读,如果有setter则可写),依此类推?我想要一种机制,让我可以选择跳过一些getter / setter夫妇,最好是手工完成工作。
答案 0 :(得分: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
答案 1 :(得分:2)
使用metaclass查找Get*
和Set*
等所有属性,并为该类添加适当的属性。有一个class属性,您可以将其设置为包含将被跳过的属性的序列。有关在班级中设置属性的详细信息,请参阅this answer。
答案 2 :(得分:1)
小心使用魔法,特别是神奇地改变其他人的绑定。这有缺点
考虑一下处理你正在使用的库是否更有意义。
答案 3 :(得分: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