classmethod中受保护的属性

时间:2016-06-26 04:14:48

标签: python attributes class-method pylint

Python约定建议使用下划线继续保护属性的名称。据我所知,受保护的属性只应在给定的类及其子类中使用。当我尝试在备用初始化器中使用受保护的属性时,你能否为我提供一些关于为什么pylint返回 protected-access 警告的直觉,例如。

class Test(object):

    def __init__(self, name):
        self.name = name
        self._count = 0
        self._bound = 1  # max value

    @classmethod
    def specific_state(cls, name, bound):
        test = cls(name)
        test._bound = bound

我确实理解在这个特定的情况下(在上面的例子中给出)我处理一个对象的实例,但它仍然在类定义中,因此从我的角度看似乎没问题。在这个问题上,pylint是否过于严格,还是我误解了?

2 个答案:

答案 0 :(得分:2)

在我看来,pylint在这一点上过于活跃。我怀疑在这方面会有太多不同意见。我无法为pylint开发人员说话,但我会猜测这对于类型推理来说更像是一个问题,而不一定被认为是他们的理想行为。

不同的人可能会告诉您关于引用带有下划线的成员的不同意见。我的个人意见是

  • 如果它在同一个模块中,那就是公平游戏
    • 但是,你仍然应该尽可能地限制这一点,以避免在可能的情况下将类/功能实现捆绑在一起。
  • 如果该成员属于另一个模块,则不再是公平游戏,应将其视为实施细节。
    • 将这些实现绑定在一起本身就很危险,因为对一个实现的更改可能会在没有警告的情况下轻易破坏其他代码。

所以这意味着,如果我在Foo中定义了类_member(包含成员foo.py),并且我创建了Foo的子类(让我们调用它{{ 1}})在Bar中,我不相信bar.py应该明确引用Bar属性。但是,如果您将_member移至Bar,那么就可以了。事实上,也应该允许班级foo.py(也在Baz中定义)依赖foo.py的内部 - 但最好有充分的理由这样做。

大多数情况下,我对下划线前缀成员的处理方式并不好,因为"受保护" (在Java意义上)。我认为它们应被视为"实施细节"。受保护在Java中工作得更好,因为如果您更改实现(例如删除受保护的成员),代码将在编译时失败并让您知道您的子类所依赖的受保护成员不再存在。 Python没有内置的安全防护装置。

因为下划线带有前缀的名称是"实现细节",如果它是同一个类(就像你在问题中描述的那样),那么它是相同的实现,所以(对我来说,允许访问这些成员是一个明智的选择。我Foo没有第二个想法: - )。

答案 1 :(得分:1)

pylint.checkers.classes.ClassChecker方法中的_check_protected_attribute_access

'''Given an attribute access node (set or get), check if attribute
access is legitimate. Call _check_first_attr with node before calling
this method. Valid cases are:
* self._attr in a method or cls._attr in a classmethod. Checked by
_check_first_attr.
* Klass._attr inside "Klass" class.
* Klass2._attr inside "Klass" class when Klass2 is a base class of
    Klass.
'''

您可以在上述案例中看到您的案例。因此可以假设protected-access警告是合法的。

可是:

    来自pylint代码本身的
  1. 发生了完全相同的情况。 (例如exceptions.py:338):

    # pylint: disable=protected-access
    exc = exc._proxied
    

    所以基本上他们在那种情况下禁用了他们的检查员。

  2. 在c ++中,以下代码有效:

            class X
    {
    private:
        int a;
    protected:
        int b;
    public:
        static void staticMethod(X& x)
        {
            x.a = 1;
            x.b = 1;
        }
    };
    

    因此,访问静态方法中的protected / private成员是有效的。

  3. 我想说pylint在这种情况下过于敏感。您可以使用注释来禁用那里的检查器。产生警告的原因可能是静态检查器难以实现更复杂的行为。