How do I use/reuse implementations in the parent class when using the classmethod
approach for implementing factory functions?
In the example below, class A
is fine, but class B
is broken.
class A(object):
def __init__(self, **kwds):
self.__dict__.update(kwds)
@classmethod
def from_jdata(cls, data):
if '_id' in data:
data['uuid'] = data['_id']
del data['_id']
return cls(**data)
class B(A):
def __init__(self, **kwds):
super(B, self).__init__(**kwds)
@classmethod
def from_jdata(cls, data):
# goal: make an instance of B,
# using the logic that is implemented in A.from_jdata
# But does some extra stuff, akin to:
res = A.from_jdata(B, data)
res.__dict__['extra']='set'
return res
The context is that I'm trying to instantiate instances based on JSON configuration data. The inheritance hierarchy is deeper than just two classes, i.e. there are a number of children of class B
. The root of the inheritance hierarchy does some useful stuff in the factory function. Children classes should re-use that but add on some additional operations.
Use super
, of course:
class A(object):
def __init__(self, **kwds):
self.__dict__.update(kwds)
@classmethod
def from_jdata(cls, data):
if '_id' in data:
data['uuid'] = data['_id']
del data['_id']
return cls(**data)
class B(A):
def __init__(self, **kwds):
super(B, self).__init__(**kwds)
@classmethod
def from_jdata(cls, data):
# goal: make an instance of B,
# using the logic that is implemented in A.from_jdata
# But does some extra stuff, akin to:
res = super().from_jdata(data)
# res = super(B, cls).from_jdata(data) # in python 2
res.__dict__['extra']='set'
return res
In action:
In [6]: b = B.from_jdata({'_id':42, 'foo':'bar'})
In [7]: vars(b)
Out[7]: {'foo': 'bar', 'uuid': 42, 'extra': 'set'}
Note, what you were trying to do won't work because @classmethod
creates a descriptor that binds the class when called from either the class or the instance. You would have to access the raw function using something like:
res = A.__dict__['from_jdata'].__func__(B, data)
To make it work, but just use super
, that's what it is for.