[使用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流程,但是无法解释从不同类调用的函数。有人可以帮我吗
答案 0 :(得分:3)
您误解了super()
的作用。 super()
不会更改self
引用的类型。 super(..., self).method()
仍将传递self
对所调用方法的引用,因此在所有三种情况下,self
都是Grandchild()
实例。
这意味着在所有情况下,self.aux_func()
都遵循正常的属性解析顺序,对于Grandchild()
实例,self.aux_func()
将始终找到Child.aux_func
并对其进行调用。
唯一不同的是,更改的唯一查询是您在super()
对象本身上查询的属性。如果您需要更多此类更改,则需要再次使用super()
,或,您需要为aux_func()
函数赋予每个名称不同班。一种实现方法是将方法 class私有。
可以通过在函数的开头(但不能在结尾处)用两个下划线命名函数来实现后者。然后在编译时对这些名称进行更改 ,以便在所引用的所有位置插入类名称:
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())
请参见Reserved classes of identifiers documentation:
__*
类私有名称。在类定义的上下文中使用时,此类别中的名称将被重写,以使用变形的形式来帮助避免基类和派生类的“私有”属性之间的名称冲突。
私人名称处理:当在类定义中以文本形式出现的标识符以两个或多个下划线字符开头且不以两个或多个下划线结尾时,则被视为该类的私有名称。在为专用名称生成代码之前,专用名称会转换为更长的格式。转换将在类名前面插入类名,并删除前导下划线,并插入单个下划线。例如,出现在名为
__spam
的类中的标识符Ham
将转换为_Ham__spam
。这种转换与使用标识符的语法上下文无关。
通过为__aux_func
使用类私有命名,在Parent
上定义的方法中对它的任何引用都将查找并找到_Parent__aux_func
,并在{{1 }}会查找并找到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()
。类专用名称实际上只是在打算由第三方代码子类化的API中意图,而对子类可以使用的名称没有太多限制。