Python3:更改继承

时间:2018-04-16 16:24:59

标签: python python-3.x oop

我认为我想改变一个类的继承性,但后来我读了这个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.FDFrame.E)和Imp.FEImp)的精确副本以及新的基类({{1所以我们有以下结构:

Imp.New

Imp.New(Frame.B)

Imp.FD(Imp.New)

Imp.FE(Imp.New)

Imp.A(Imp.FD)

但是我们现在有两个(几乎相同)的两个类的副本(Imp.B(Imp.FE) = Imp.FDFrame.D = Imp.FE)这使得开发等有点痛苦

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

有人可以建议解决我的问题吗?

增加: Pass a parent class as an argument?上接受的答案显示了一种在函数内定义类的方法,以便可以选择父类。我可以使用这种技术,以便Frame.BFrame.D都有可变的父类,但感觉有点hacky并且在人们使用它时不会破坏帮助功能/文档字符串吗?

这似乎不是一个特别不寻常的情况,当然这种事情肯定会有一些协议吗?

1 个答案:

答案 0 :(得分:1)

您可以尝试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