首页 > 解决方案 > Python类继承——属性混淆

问题描述

在我看来,当程序员必须使用由其他人开发的类时,Python 存在固有的困难,他/她有关于他/她的基本文档(如何构造它,可用的函数等)但没有其实现的细节. 当然,当事情开始出错时,人们可以检查源代码,但所说的类可能是完全健壮的,直到有人想要对其进行子类化。

考虑这个简单的例子:-

class Base():
    def __init__(self):
        self._n = 99

    @property
    def n(self):
        return self._n

    @n.setter
    def n(self, n):
        self._n = n

    def func(self):
        print(self.n)

这里的关键是 Base 有一个函数,它在某种程度上依赖于属性 _n。

我现在决定要开发一个子类 Base 的类。所以,我写这个:-

class Myclass(Base):
    def __init__(self, n):
        super().__init__()
        self.n = n

现在我遇到了麻烦,因为我刚刚在我的超类中删除了一个属性,并且可能完全破坏了它的功能。

是否有针对此潜在问题的任何开发模式或任何其他形式的防御?

标签: python

解决方案


您可以通过对“private”* 属性使用名称修饰来避免“切换”超类的属性。名称以两个下划线**开头的属性将自动修改其名称,以免与超类中声明的名称发生冲突。

class A:
    def __init__(self):
        self.__x = 1
    def get_A_x(self):
        return self.__x

class B(A):
    def __init__(self):
        super().__init__()
        self.__x = 2
    def get_B_x(self):
        return self.__x

obj = B()
print(obj.get_A_x(), obj.get_B_x())
# prints "1 2"

在最好的情况下,超类总是被编写为使用名称修饰来保护它自己的“私有”属性。如果不是,那么至少您可以确定子类中的名称损坏属性不会与它们发生冲突;仍然存在子类的公共属性可能与超类的未知“私有”属性发生冲突的风险。在这种情况下,您能做的最好的事情(除了在他们的问题跟踪器上打开一个问题)将尝试通过检查__dict__超类实例的属性来找出超类声明的未记录属性,然后避免与这些名称发生冲突。

*当然在 Python 中,没有属性是真正私有的。甚至可以从声明它们的类外部访问名称损坏的属性,如果它们是通过它们的损坏名称访问的。
**不包括“dunder 方法”之类__init__的,或任何其他也以两个或多个下划线结尾的名称。


推荐阅读