python - Python使用super与孙子继承父母和孩子
问题描述
[使用 Python3.6] 我有一个设计,其中孙子继承了父子(父子)。
class Parent:
def aux_func(self):
return "[parent aux]"
def main_func(self):
print("[parent main]" + self.aux_func())
class Child(Parent):
def aux_func(self):
return "[child aux]"
def main_func(self):
print("[child main]" + self.aux_func())
class Grandchild(Child, Parent):
@classmethod
def do_something(cls):
g = Grandchild()
g.main_func()
super(Child, g).main_func()
Parent.main_func(g)
Grandchild.do_something()
结果是——
[child main][child aux]
[parent main][child aux]
[parent main][child aux]
从 Parent 调用函数会导致 aux_func 从 Child 类解析。我试图通过 MRO 流程,但无法解释从不同类调用的函数。有人可以帮我吗
- 为什么会这样?
- 实现 [parent main][parent aux] 的解决方法是什么?
解决方案
你误解了什么super()
。super()
不会改变self
引用的类型。super(..., self).method()
仍然会将该self
引用传递给被调用的方法self
,在所有三种情况下,Grandchild()
实例也是如此。
这意味着在所有情况下,都self.aux_func()
遵循正常的属性解析顺序,Grandchild()
例如,self.aux_func()
总是会找到Child.aux_func
并调用它。
换句话说,唯一改变的查找是您在super()
对象本身上查找的属性。如果您需要更多此类更改,则需要super()
再次使用,或者您需要为每个类赋予不同aux_func()
的函数名称。一种方法是使方法类成为私有的。
后者可以通过在开头(但不是结尾)用两个下划线命名您的函数来完成。然后在编译时更改此类名称,以将类名注入到它所引用的所有位置:
class Parent:
def __aux_func(self):
# class private to Parent
return "[parent aux]"
def main_func(self):
# any reference to __aux_func *in this class* will use
# the Parent class-private version
print("[parent main]" + self.__aux_func())
class Child(Parent):
def __aux_func(self):
# class private to Child
return "[child aux]"
def main_func(self):
# any reference to __aux_func *in this class* will use
# the Child class-private version
print("[child main]" + self.__aux_func())
__*
类私有名称。此类别中的名称,当在类定义的上下文中使用时,会被重新编写以使用重整形式,以帮助避免基类和派生类的“私有”属性之间的名称冲突。
Private name mangling:当在类定义中以文本形式出现的标识符以两个或多个下划线字符开头并且不以两个或多个下划线结尾时,它被认为是该类的私有名称。在为私有名称生成代码之前,私有名称会转换为更长的形式。转换插入类名,删除前导下划线并在名称前面插入一个下划线。例如,
__spam
出现在名为的类中的标识符Ham
将转换为_Ham__spam
. 此转换与使用标识符的语法上下文无关。
通过使用类私有命名__aux_func
,从定义的方法中对它的任何引用都Parent
将查找和查找_Parent__aux_func
,并且对同名的任何引用都Child
将查找和查找_Child__aux_func
。这两个名称是不同的,因此不会冲突:
>>> class Grandchild(Child, Parent):
... @classmethod
... def do_something(cls):
... g = Grandchild()
... g.main_func()
... super(Child, g).main_func()
... Parent.main_func(g)
...
>>> Grandchild.do_something()
[child main][child aux]
[parent main][parent aux]
[parent main][parent aux]
实现此目的的另一种方法是明确地使用不同的名称;说parent_aux_func()
和child_aux_func()
。类私有名称实际上仅适用于旨在由第三方代码子类化的 API,而对子类可以使用的名称没有太多限制。
推荐阅读
- python - 如何在python中设置超时并打印时间倒计时
- angular - 发生错误:无法读取 null 的属性“nativeElement”
- google-apps-script - 自动更改 Google 表单回复的日期格式
- mysql - docker 中的 MySQL 不会保留对已配置卷的更改
- bash - 将 bash 计时器附加到文件
- javascript - 动作是未定义的或不可见的,即使它看起来写得正确
- heroku - Heroku 和 axios
- google-maps-api-3 - 如何通过再次单击标记关闭打开的谷歌地图信息窗口
- python - 如何在 Matplotlib 中获取散点图的最小(或最大)边界
- c# - 使用 GetType().GetTypeInfo().GetDeclaredProperty 为现有属性设置值时 C# 参考错误