我有两个类A
和B
,它们都有一个返回字符串的方法get_type()
,在两个类的__init__()
中调用该方法来设置示例属性self.type
。现在有一个继承自A
和B
的子类,在它里面's __init__()
,它以A
或B
的示例作为参数,根据它是用A
还是B
的示例示例化的,我调用父对象对应的__init__()
,大概是因为多重继承的查找顺序,始终调用A
父级的get_type()
方法,即使C
是使用B
示例示例化的。请参阅下面的代码:
class A:
def __init__(self):
self.type = self.get_type()
def get_type(self):
return 'A'
class B:
def __init__(self):
self.type = self.get_type()
def get_type(self):
return 'B'
class C(A, B):
def __init__(self, instance):
if isinstance(instance, A):
A.__init__(self)
print('Inheriting from A')
else:
B.__init__(self)
print('Inheriting from B')
a = A()
b = B()
c = C(b)
print(a.type, b.type, c.type)
>>> Inheriting from B
>>> A B A
所以我希望c.type
是'B',因为它继承自B
类。我可以使用super()
函数来获得我想要的行为吗?
3条答案
按热度按时间umuewwlo1#
除了你为什么要这么做之外,下面是你的要求:
当你有冲突的(或潜在冲突的)方法名时,Python的机制是在方法名前加上两个下划线(
__
),大多数文章和第三方文档都把这称为“在Python中创建私有属性/方法的方法”,但事实并非如此:Python根本不使用私有属性,而是按照惯例(使用单个_
作为前缀)。使用两个下划线,而不是一个,触发方法或属性的内部名称转换,以透明的方式将类名作为前缀添加到目标方法中。这被称为“名称修饰”。
对于您的代码,它将在没有进一步更改的情况下开箱即用。如果您检查运行的代码(例如
print(dir(self))
),您将看到您的方法将分别命名为A._A__get_type
和B._B__get_type
(这两个方法都将出现在C
中)但是,请注意
C
中的任何方法都不能“看到”.get_type
:这个方法现在对每个超类都是私有的。2两者都可以通过转换后的名字从C中访问,如果显式使用的话,很坚韧。fjnneemd2#
看起来您正在尝试执行某种类型的 * 条件继承 ,这里是similar question, 条件继承 * 可以被视为反模式,因为它会使代码更难理解和维护,无论如何,您可以使用一些已知的模式(如 Wrapper/Decorator 模式)来实现它,在注解中有一个很好的例子。2你可以使用的另一个模式是 Composition 模式,下面是一个例子:
方法
get_type_wrapped
只是给予了一个 shared 方法的例子,其思想只是创建一个局部类,该局部类 * 组合 * 类C
和另一个作为参数传递的类,并返回它的一个示例。ni65a41a3#
我想我明白你的目标是什么。首先,让我们看看为什么你的方法是有缺陷的:
当前方法的问题
根据您的类布局,
C
既是A
又是B
。原因是继承形成了“是a”关系。由此,隐含的期望是该关系满足“Liskov替换原理”,也就是说,您可以在代码需要A
或B
的地方提供C
。我相信这不是您的意图,尽管很接近。可能的替代方法
您在注解中提到,
A
和B
都有一个公共接口,甚至可以实现为抽象基类(https://docs.python.org/3/library/abc.html)。我们称之为I
(如在I界面中)使讨论更容易。它是作为ABC存在还是仅仅是一种约定并不重要(提供类似方法的类,又名“Duck Typing”),Python在这方面是允许的。有了
I
接口,我们实际上就有了三个类,它们都实现了这个接口。如果你现在编写代码期望I
(而不是具体的A
或B
),你应该能够将A
、B
或C
中的任何一个传递给它(同样,Liskov替换)。此外,
C
不必同时继承A
和B
,它可以包含其中之一。实际上,它可以只包含一个I
,以便将来更容易地扩展到更多此类类型。I
所需的任何方法(您的草图中只有get_type()
)可以通过简单地将其转发到包含的I
示例来实现。注解
C
放在首位?我怀疑它是否需要成为一个类。不是所有的东西都是类,也不是所有的东西都应该是类!我的猜测是大部分都被一个公共的抽象基类淘汰了。我能看到的唯一真实的的优点是交换底层A
或B
的能力,从而切换行为。get_type()
是一种代码气味。我有一种想法,你正在实现一个类型系统(Python有它自己的),你正在尝试实现多态性或类似的东西。这不一定是一个问题,但它可能需要一些审查在未来。