Как добиться наследования с помощью фабричных функций метода класса
Как использовать / повторно использовать реализации в родительском классе при использовании classmethod
подход для реализации фабричных функций?
В приведенном ниже примере class A
хорошо, но class B
сломано.
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
Контекст заключается в том, что я пытаюсь создать экземпляры на основе данных конфигурации JSON. Иерархия наследования более глубока, чем просто два класса, т.е. class B
, Корень иерархии наследования делает некоторые полезные вещи в функции фабрики. Детские классы должны использовать это повторно, но добавить некоторые дополнительные операции.
1 ответ
Использование super
, конечно:
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 [6]: b = B.from_jdata({'_id':42, 'foo':'bar'})
In [7]: vars(b)
Out[7]: {'foo': 'bar', 'uuid': 42, 'extra': 'set'}
Обратите внимание, что вы пытались сделать не получится, потому что @classmethod
создает дескриптор, который связывает класс при вызове из класса или экземпляра. Вам нужно было бы получить доступ к сырой функции, используя что-то вроде:
res = A.__dict__['from_jdata'].__func__(B, data)
Чтобы заставить это работать, но просто используйте super
вот для чего это.