【问题标题】:Python3: Changing inheritancePython3:改变继承
【发布时间】:2018-04-16 16:24:59
【问题描述】:

我以为我想改变一个类的继承,但后来我读到了这个How to dynamically change base class of instances at runtime?,它说这是一个坏主意。我学到了一个艰难的方法,当很多人在 SO 上说不要这样做但你还是这样做了,那么你最终会后悔的。但是,我正在努力寻找如何避免它。所以我想提出我的问题,看看是否有人对如何克服这个问题有任何意见。

我有两个库 FrameImp

框架

Frame 是类的集合,它们充当开发工具的一种框架。

这个库中有五个类。

Frame.A(metaclass=ABCMeta):

是一个抽象类,一切都将从中继承。

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

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

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

由于我们不想要大量重复的代码,我们考虑添加一个具有公共方法的类,因此 Imp.AImp.B 都可以继承自。问题是这些函数太具体了,不能放在 Frame 库中,在 Imp 库中没有 Frame.DFrame.E 是没有意义的。

可以在Imp 中创建Frame.D (Imp.FD) 和Frame.E (Imp.FE) 的精确副本,再加上新的基类(Imp.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 都有可变的父类,但感觉有点笨拙,当人们使用它时它不会弄乱帮助函数/文档字符串吗?

这似乎不是什么特别的情况,这种事情肯定有一些协议吗?

【问题讨论】:

    标签: python python-3.x oop


    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2018-08-13
      • 1970-01-01
      • 2018-01-21
      • 1970-01-01
      • 1970-01-01
      • 2017-10-30
      • 2012-05-16
      • 2020-10-24
      • 2014-08-01
      相关资源
      最近更新 更多