我认为我想改变一个类的继承性,但后来我读了这个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
)的精确副本以及新的基类({{1所以我们有以下结构:
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
那么这将是完美的。然而,显然这是不好的做法:How to dynamically change base class of instances at runtime?
有人可以建议解决我的问题吗?
增加:
Pass a parent class as an argument?上接受的答案显示了一种在函数内定义类的方法,以便可以选择父类。我可以使用这种技术,以便Frame.B
和Frame.D
都有可变的父类,但感觉有点hacky并且在人们使用它时不会破坏帮助功能/文档字符串吗?
这似乎不是一个特别不寻常的情况,当然这种事情肯定会有一些协议吗?
答案 0 :(得分:1)
您可以尝试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