Pylint W0212 受保护访问

问题描述 投票:0回答:3

在Python中,带有一个下划线前缀表示不应在其类之外访问成员。 这似乎是基于每个类的,例如 JavaC++

但是,pylint 似乎在每个对象的基础上强制执行此约定。 有没有办法允许每个班级访问而不诉诸

#pylint: disable=protected-access

class A:
    def __init__(self):
        self._b = 5

    def __eq__(self, other):
        return self._b == other._b

结果:

pylint a.py
a.py:6: W0212(protected-access) Access to a protected member _b of a client class

Pylint 在此处描述了该消息。

python private-members pylint
3个回答
34
投票

pylint 不知道

other
是什么类型(应该如何,您可以将 A 的实例与所有内容进行比较),因此出现警告。我认为没有办法禁用警告。

您可以通过在该行附加

# pylint: disable=W0212
来仅禁用该行的警告。


3
投票

Christian Geier 关于为什么会出现错误以及如何禁用它的说法是正确的。

不过,我鼓励您考虑更改代码:pylint 告诉您一些重要的事情。从您的示例代码来看,您似乎想使用 eq 将 A 类的对象与 A 类的其他对象进行比较,但您的示例不能保证调用者不会尝试

A() == C()
。当您检查
True
时返回
Circle()._radius == Sphere._radius
似乎可能会导致问题。

请参阅此 stackoverflow 线程,了解如何处理此问题的讨论。


0
投票

__eq__
方法

问题的第一部分已在许多帖子中得到解决:

__eq__
方法应该能够将您的
A
实例与其他类型的任意对象进行比较,而不仅仅是与其他
A
实例进行比较。这是推荐的实施方式
__eq__
:

class A:
    def __init__(self, value) -> None:
        self.__private = value

    def __eq__(self, other) -> bool:
        if not isinstance(other, A):
            return NotImplemented
        return <logic to compare two A instances>

备注:

  • 或者,您可能要求

    other
    属于相同的基类:
    type(other) == A
    ,它比
    isinstance(...)
    版本更严格(后者也允许子类)。

  • 在某些示例中,使用

    isinstance(other, self.__class__)
    type(self) == type(other)
    ,但这通常是错误的:当
    B() == C()
    NotImplemented
    B
    的两个不同子类时,
    C
    会给出
    A

  • 有些人还在类

    __class__
    的定义主体中使用
    A
    来表示
    A
    。虽然它在 python 中运行良好,但 mypy 给出了
    error: Name "__class__" is not defined  [name-defined]

  • 如果

    self
    other
    没有可比性,建议返回
    NotImplemented
    。但是,
    type(NotImplemented)
    不应该包含在
    __eq__
    的返回类型提示中,只需将其保留为
    bool
    即可。

受保护的属性。

问题的第二部分是关于受保护属性的比较,没有 pylint 显示“受保护访问”错误。如果你想比较以双下划线开头的私有属性,由于名称修改,它会变得更加混乱:

other.__private
表示类
getattr(other, '_A__private')
体内的
A
,与类中定义的
other.__private
无关。类的主体
B
(意思是
getattr(other, '_B__private')
)。即使
B
A
的真正子类,属性
_A__private
也只能用于
A
方法访问,而不能用于
B
方法。考虑到这一点,在我们确保
B
A
的子类之后,我们可能想要将
self.__private
other.__private
进行比较。

  1. 比较属性字典是一种常见的做法。这非常方便,因为
    dict
    对象逐项进行比较,并且存储为
    A
    的类
    _A__private
    的私有属性也可以正确访问,而 pylint 不会抱怨受保护的访问。但是,如果子类与基类相比具有额外的属性,则比较结果始终为
    False
    。另外,如果定义了
    __slots__
    ,则没有
    __dict__
    属性。
            return self.__dict__ == other.__dict__
  1. 另一种方法是直接检查相关字段。即使我们已经检查过
    other
    属于同一类,并且理论上访问私有属性是安全的,我们也必须手动静音 pylint。
            return self.__private == other.__private  # pylint: disable=W0212
  1. 一个明显的解决方法是使用 pylint 不会抱怨的
    getattr()
    ,但明确引用 python 的名称修饰应该是一些丑陋黑客的警告信号。另请注意,当
    other.__private
    (或更确切地说
    AttributeError
    )未在
    __private
    上定义时,
    _A__private
    会引发
    other
    ,而
    getattr()
    会默默地返回
    None
            return self.__private == getattr(other, '_A__private')
  1. 还可以定义一个公共接口来执行与私有属性的比较。这样的接口不仅过于复杂,而且理论上还会泄露私有数据的信息。
            return other.cmp_private(self.__private)

    def cmp_private(self, value) -> bool:
        return self.__private == value
© www.soinside.com 2019 - 2024. All rights reserved.