首页 > 解决方案 > 如何使用类方法工厂函数实现继承

问题描述

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. 继承层次的根在工厂函数中做了一些有用的事情。子类应该重用它,但添加一些额外的操作。

标签: pythoninheritancefactory-pattern

解决方案


使用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'}

请注意,您尝试执行的操作将不起作用,因为在从class 或 instance@classmethod调用时创建了一个绑定类的描述符。您必须使用以下方式访问原始函数:

res = A.__dict__['from_jdata'].__func__(B, data)

为了让它工作,但只是使用super,这就是它的用途。


推荐阅读