我以为我想更改类的继承,但是后来我读了这个How to dynamically change base class of instances at runtime?,说这是一个坏主意。我已经学到了很难的方法,当很多人这样说不这样做,但是无论如何还是这样做,最终您会后悔。但是,我正在努力寻找如何避免这种情况的方法。因此,我想提出我的问题,看看是否有人对如何解决这个问题有任何意见。
我有两个库Frame
和Imp
。
帧: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.A
和Imp.B
中相同的方法。
由于我们不需要大量重复的代码,因此我们考虑添加一个具有公用方法的类,因此Imp.A
和Imp.B
都可以继承。问题是这些功能在Frame
库中太具体了,不能在Frame.D
库中没有Frame.E
和Imp
了。
可以在Frame.D
和新的基类(Imp.FD
)中创建Frame.E
(Imp.FE
)和Imp
(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.D
和Imp.FE
= Frame.E
)的两个(几乎相同)副本,这使开发等工作有些痛苦。
如果我可以只创建Imp.New(Frame.B)
并使用Frame.D
和Frame.E
,但只需修改为继承自Imp.New
而不是Frame.B
,那将是完美的。但是,显然这是不好的做法:How to dynamically change base class of instances at runtime?
谁能建议我的问题的解决方案?
加成:
在Pass a parent class as an argument?处可接受的答案显示了一种在函数内部定义类的方法,以便人们可以选择父类。我可以使用这种技术,以便Frame.D
和Frame.E
都具有可变的父类,但是感觉有些不客气,当人们使用它时,它会否破坏帮助功能/文档字符串?
这似乎不是特别不寻常的情况,对于这种事情肯定要有一些协议吗?
最佳答案
您可以尝试composition instead of inheritance或using mixins
这可能是组成的一种情况,但是为了以防万一,我包括了mixins。
这是使用想象的Frame
和Imp
类的示例。
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