我以为我想更改类的继承,但是后来我读了这个How to dynamically change base class of instances at runtime?,说这是一个坏主意。我已经学到了很难的方法,当很多人这样说不这样做,但是无论如何还是这样做,最终您会后悔。但是,我正在努力寻找如何避免这种情况的方法。因此,我想提出我的问题,看看是否有人对如何解决这个问题有任何意见。

我有两个库FrameImp

帧:

Frame是用作工具开发框架的类的集合。

该库中有五个类。

Frame.A(metaclass=ABCMeta)

是所有内容都将继承的抽象类。

下一级别分为两种类型的对象:
Frame.B(A)Frame.C(A)

Frame.C没有更多的子级,但是Frame.B并再次分叉:
Frame.D(B)Frame.E(B)

IMP:
我们决定要使用Frame框架来创建特定的工具并创建两个类
Imp.A(Frame.D)Imp.B(Frame.E)对象。但是事实证明,我们创建了许多在Imp.AImp.B中相同的方法。

由于我们不需要大量重复的代码,因此我们考虑添加一个具有公用方法的类,因此Imp.AImp.B都可以继承。问题是这些功能在Frame库中太具体了,不能在Frame.D库中没有Frame.EImp了。

可以在Frame.D和新的基类(Imp.FD)中创建Frame.EImp.FE)和ImpImp.New)的精确副本,因此我们具有以下结构:

Imp.New(Frame.B)

Imp.FD(Imp.New)

Imp.FE(Imp.New)

Imp.A(Imp.FD)

Imp.B(Imp.FE)

但是,我们现在有两个类(Imp.FD = Frame.DImp.FE = Frame.E)的两个(几乎相同)副本,这使开发等工作有些痛苦。

如果我可以只创建Imp.New(Frame.B)并使用Frame.DFrame.E,但只需修改为继承自Imp.New而不是Frame.B,那将是完美的。但是,显然这是不好的做法:How to dynamically change base class of instances at runtime?

谁能建议我的问题的解决方案?

加成:
Pass a parent class as an argument?处可接受的答案显示了一种在函数内部定义类的方法,以便人们可以选择父类。我可以使用这种技术,以便Frame.DFrame.E都具有可变的父类,但是感觉有些不客气,当人们使用它时,它会否破坏帮助功能/文档字符串?

这似乎不是特别不寻常的情况,对于这种事情肯定要有一些协议吗?

最佳答案

您可以尝试composition instead of inheritanceusing mixins

这可能是组成的一种情况,但是为了以防万一,我包括了mixins。

这是使用想象的FrameImp类的示例。

class Frame(object):
    def do_thing(self, stuff):
        raise NotImplementedError


class A(Frame):
    def __init__(self, thingy):
        self.thingy = thingy

    def do_thing(self, stuff):
        return stuff + self.thingy


class B(Frame):
    def __init__(self, thingy):
        self.thingy = thingy

    def do_thing(self, stuff):
        return stuff - self.thingy


class CrazyB(B):
    def __init__(self, thingy):
        self.dingus = 5
        super(CrazyB, self).__init__(thingy)

    def go_crazy(self):
        return self.dingus + self.thingy - 10**10


组成

class Imp(object):
    def __init__(self, frame, stuff):
        self.frame = frame
        self.stuff = stuff

    def be_impish(self):
        raise NotImplementedError

    def do_frame_stuff(self):
        return self.frame.do_thing(self.stuff)

# OR ALSO COMPOSITION

class ImpAlternate(object):
    frame_class = None

    def __init__(self, frame_arg, stuff):
        self.frame = self.frame_class(frame_arg)
        self.stuff = stuff

    def be_impish(self):
        raise NotImplementedError

    def do_frame_stuff(self):
        return self.frame.do_thing(self.stuff)


class ImpA(ImpAlternate):
    frame_class = CrazyB

    def be_impish(self):
        return self.frame.go_crazy()


混合

class ThingyShower(object):
    def show_thingy(self):
        try:
            thingy =  str(getattr(self, 'thingy'))
        except AttributeError:
            thingy =  'no thingy'
        return 'thingy: {}'.format(thingy)


class ImpB(B, ThingyShower):
    def __init__(self, stuff):
        super(ImpB, self).__init__(stuff)


实际上:

>>> x = ImpA(11, 22)
>>> print(x.be_impish())
-9999999984
>>> print(x.do_frame_stuff())
11

>>> y = ImpB(25)
>>> print(y.do_thing(10))
-15
>>> print(y.show_thingy())
thingy: 25

10-07 13:37
查看更多