Python - 如何使用 super(<class>, self) 访问 parent 类 中的实例属性?

Python - how to access instance properties in parent classes with super(<class>, self)?

请解释为什么我不能使用 super(class, self) 访问 class 继承层次结构中更高层 class 中定义的属性,以及如何访问它们。

根据文档,super(class, self 应该返回一个代理 object,通过它我可以访问 parent class 实例中的 def name()

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class.

The object-or-type determines the method resolution order to be searched. The search starts from the class right after the type.

For example, if mro of object-or-type is D -> B -> C -> A -> object and the value of type is B, then super() searches C -> A -> object.

我认为 super(Parent) 会为具有 def name().

的祖父母 object 提供代理
class GrandParent:
    def __init__(self):
        self._name = "grand parent"

    @property
    def name(self):
        return self._name


class Parent(GrandParent):
    def __init__(self):
        super().__init__()
        self._name = "parent"

    @property
    def name(self):
        return super().name


class Child(Parent):
    def __init__(self):
        super().__init__()
        self._name = "child"

    @property
    def name(self):
        return super(Parent).name


print(Child().name)
---
AttributeError: 'super' object has no attribute 'name'

没有(class, self),它returns ... child 属性。显然我还没有理解 selfsuper 在 Python 中是如何工作的。请建议查看哪些资源以充分理解行为和设计。

class GrandParent:
    def __init__(self):
        self._name = "grand parent"

    @property
    def name(self):
        return self._name


class Parent(GrandParent):
    def __init__(self):
        super().__init__()
        self._name = "parent"

    @property
    def name(self):
        return super().name


class Child(Parent):
    def __init__(self):
        super().__init__()
        self._name = "child"

    @property
    def name(self):
        return super().name


print(Child().name)
---
child

self 总是指同一个对象。当您执行 super().__init__() 时,父级 __init__ 中的 self 就是您的 Child 实例。 GrandParent.__init__ 只是在该对象上设置一个属性。通过链接所有这些 __init__s,你实际上只是这样做:

o = object()
o._name = 'grand parent'
o._name = 'parent'
o._name = 'child'

您只是覆盖 _name 属性,其中只有一个。所有不同的 @property 只是 return 这个 _name 属性的值,你的对象只有一个,它的值是 'child'.

如果您希望对象的每个父对象都有一个单独的 _name 属性,您实际上必须创建单独的属性。最简单的方法可能是使用 Python 的双下划线 name mangling a.k.a。 “私有属性”:

>>> class A:
...   def __init__(self):
...     self.__foo = 'bar'
...   @property
...   def foo(self):
...     return self.__foo
...
>>> class B(A):
...   def __init__(self):
...     super().__init__()
...     self.__foo = 'baz'
...   @property
...   def foo(self):
...     return super().foo
... 
>>> B().foo
'bar'
>>> vars(B())
{'_A__foo': 'bar', '_B__foo': 'baz'}

实际属性命名为 _A__foo_B__foo,因此不会相互冲突。