Reputation: 563
I am writing an API client for a RESTful web service. The problem I am having is one of the objects returned by the API has many subtypes. In total, there are over 200 properties across the subtypes, some being duplicates.
Those that are used by all subtypes I've defined in the parent class. However, there are some properties that only get used by, let's say, 5 of the children. In a normal case, I would just add another layer to the parent/child model, but children mix and match which properties they have in common. Here's an example
class Parent(object):
@property
def apiLinks(self):
pass
@apiLinks.setter
def apiLinks(self, value):
pass
class Child1(Parent):
@property
def interval(self):
pass
@interval.setter
def interval(self, value):
pass
@property
def duration(self):
pass
@apiLinks.setter
def duration(self, value):
pass
class Child2(Parent):
@property
def interval(self):
pass
@interval.setter
def interval(self, value):
pass
@property
def prefix(self):
pass
@prefix.setter
def prefix(self, value):
pass
class Child3(Parent):
@property
def duration(self):
pass
@duration.setter
def duration(self, value):
pass
@property
def prefix(self):
pass
@prefix.setter
def prefix(self, value):
pass
As you can see:
I don't want to define the same setter/getter functions more than once and same with the docstrings.
I've looked into importing properties, but that doesn't seem to be an option since they are by design members of an instance.
I've considered defining them all in the parent and looking up the instance type to decide whether or not it becomes available to instantiated children. Such as:
class Parent(object):
if isinstance(self, (Child1, Child2)):
@property
def interval(self):
pass
@interval.setter
def interval(self, value):
pass
I suppose I could save the property getter/setter methods as strings in another module and exec them into the functions and define the docstrings there as well.
interval_get = """@property
def interval(self):
\"\"\"
The interval at which the test should run.
Parameters
----------
value : int
Testing interval, allowed options: [300, 600, 900, 1800, 3600]
Returns
-------
value : int
Configured test interval
Raises
------
ValueError
If value is not one of [300, 600, 900, 1800, 3600]
TypeError
If type provided is not of type int
\"\"\"
return self._interval
"""
interval_set = """@interval.setter
def interval(self, value):
print('works')
self._interval = value
"""
class TestProp(object):
exec(interval_get)
exec(interval_set)
I'm looking for the recommended approach though. Also, I'm not interested in supporting python2.x so this code is for python3.x only. I'm fine with solutions specific to python3.7 even.
Upvotes: 2
Views: 293
Reputation: 4964
If you were using read-only data I would say use namedtuples. Store the property names in a config file as strings for each type and create the appropriate namedtuples at runtime.
As they look read/write because of the setters, maybe the 3rd-party recordclasses
mentioned in this answer will do.
Upvotes: 0
Reputation: 25205
It sounds somewhat like you are asking a design question, but design questions are often specific to the problem domain, and you aren't really providing problem domain information. That said, it sounds like you currently have a design based on inheritance. One thing you can consider is a design based on composition. In other words, all these subtypes you have may not be formal types in and of themselves, but could be compositions of fundamental data types. Given the types you mentioned i.e., intervals and durations, it seems likely that your current "parent" type could maintain lists or maps of intervals and durations, and you wouldn't need subclasses at all. Or alternatively, it seems likely that an interval or duration would have some semantic meaning, and there is a type that combines a grouped set of those things in a meaningful way.
In any case, I recommend you add more domain specific information, and possibly examples if you want more specific design help.
Upvotes: 1