Python 对继承父子的孙子使用 super
Python using super with grandchild inheriting parent and child
[使用 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]
从父项调用函数会导致 aux_func 从子项 class 解析。我试图通过 MRO 流程,但无法解释从不同 classes 调用的函数。有人可以帮我吗
- 为什么会这样?
- 实现 [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 的不同名称。一种方法是将方法 class 设为私有 .
后者可以通过在开头(但不是末尾)使用两个下划线命名您的函数来完成。然后在编译时 更改这些名称 以在所有引用它的地方注入 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:
__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.
和 Identifiers (Names) section:
Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier __spam
occurring in a class named Ham
will be transformed to _Ham__spam
. This transformation is independent of the syntactical context in which the identifier is used.
通过对 __aux_func
使用 class 私有命名,从 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()
。 Class 私有名称实际上仅 打算 在旨在由第三方代码子class 的 API 中,对子名称的名称没有太多限制[= =69=]可以用。
[使用 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]
从父项调用函数会导致 aux_func 从子项 class 解析。我试图通过 MRO 流程,但无法解释从不同 classes 调用的函数。有人可以帮我吗
- 为什么会这样?
- 实现 [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 的不同名称。一种方法是将方法 class 设为私有 .
后者可以通过在开头(但不是末尾)使用两个下划线命名您的函数来完成。然后在编译时 更改这些名称 以在所有引用它的地方注入 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:
__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.
和 Identifiers (Names) section:
Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier
__spam
occurring in a class namedHam
will be transformed to_Ham__spam
. This transformation is independent of the syntactical context in which the identifier is used.
通过对 __aux_func
使用 class 私有命名,从 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()
。 Class 私有名称实际上仅 打算 在旨在由第三方代码子class 的 API 中,对子名称的名称没有太多限制[= =69=]可以用。