Reputation: 17670
I have a big library written in C++ and someone created an interface to use it in python (2.6) in an automatic way. Now I have a lot of classes with getter and setter methods. Really: I hate them.
I want to re-implement the classes with a more pythonic interface using properties. The problem is that every class has hundreds of getters and setters and I have a lot of classes. How can I automatically create properties?
For example, if I have a class called MyClass
with a GetX()
and SetX(x)
, GetY
, SetY
, etc... methods, how can I automatically create a derived class MyPythonicClass
with the property X
(readable if there is the getter and writable if there is the setter), and so on? I would like a mechanism that lets me to choose to skip some getter/setter couples where it is better to do the work by hand.
Upvotes: 4
Views: 2712
Reputation: 11
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
Upvotes: 1
Reputation: 76683
Be careful using magic, especially magically altering other people's bindings. This has the disadvantages that
Consider whether it wouldn't make more sense just to deal with the library you are using as it came to you.
Upvotes: 1
Reputation: 304147
Here's a way to do it with a class decorator
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
Here is a slightly more complicated version that allows you to specify a list of items to skip
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
Upvotes: 9
Reputation: 798616
Use a metaclass that looks for all attributes like Get*
and Set*
and adds appropriate properties to the class. Have a class attribute that you can set to a sequence containing properties that will be skipped. See this answer for details about setting attributes in the class.
Upvotes: 2