类方法中的受保护属性
Protected attributes in classmethod
Python 约定建议在受保护属性的名称前加上下划线。据我所知,受保护的属性只能在给定的 class 及其子 class 中使用。当我尝试在替代初始化程序中使用受保护的属性时,您能否向我提供一些关于为什么 pylint returns 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
我确实理解在这种特定情况下(如上例所示)我处理了一个对象的实例,但它仍在 class 定义中,因此从我的角度来看似乎没问题。 pylint在这件事上是不是太严谨了还是我理解有误?
在我看来,pylint
这一点太过火了。我怀疑在这方面会有太多分歧。我不能代表 pylint 开发人员,但我 猜测 这更多是类型推断的问题,而不是一定被认为是他们的理想行为。
对于引用下划线开头的成员,不同的人可能会告诉你不同的看法。我个人的意见是
- 如果在同一个模块中,公平游戏
- 但是,您仍然应该尽可能地限制这种情况,以避免尽可能地将 class/function 实现捆绑在一起。
- 如果成员属于不同的模块,则不再是公平游戏,应将其视为实现细节。
- 在这里将实现捆绑在一起本质上是危险的,因为对一个实现的更改很容易在没有警告的情况下破坏其他代码。
所以这意味着如果我在 foo.py
中定义了 class Foo
(成员 _member
)并且如果我创建一个子 class Foo
(我们称它为 Bar
)在 bar.py
中,我认为 Bar
不应明确引用 _member
属性。但是,如果您将 Bar
移动到 foo.py
,那么就可以了。事实上,class Baz
(也在 foo.py
中定义)也应该被允许依赖于 Foo
的内部——但这样做最好有充分的理由.
大多数情况下,我不同意将下划线前缀成员视为 "protected"(在 Java 意义上)。我认为它们应该被视为 "implementation details"。 Protected 在 Java 中工作得更好,因为如果你更改实现(例如删除受保护的成员),代码将在编译时失败并让你知道你的 subclass 依赖的受保护成员是不再存在。 Python 没有这样的内置安全措施。
因为下划线前缀名称是 "implementation details",如果它是相同的 class(就像你在问题中描述的情况),那么它是相同的实现,所以(对我来说)允许访问这些成员是显而易见的。我会 # pylint: disable=protected-access
不假思索 :-)。
来自 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
s 代码本身发生了完全相同的情况。 (例如 exceptions.py:338):
# pylint: disable=protected-access
exc = exc._proxied
所以基本上他们在那种情况下禁用了他们的检查器。
在c++中以下代码有效:
class X
{
private:
int a;
protected:
int b;
public:
static void staticMethod(X& x)
{
x.a = 1;
x.b = 1;
}
};
因此在静态方法中访问 protected/private 成员是有效的。
我会说 pylint
在这种情况下过于敏感。您可以使用评论来禁用那里的检查器。产生警告的原因可能是静态检查器很难实现更复杂的行为。
Python 约定建议在受保护属性的名称前加上下划线。据我所知,受保护的属性只能在给定的 class 及其子 class 中使用。当我尝试在替代初始化程序中使用受保护的属性时,您能否向我提供一些关于为什么 pylint returns 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
我确实理解在这种特定情况下(如上例所示)我处理了一个对象的实例,但它仍在 class 定义中,因此从我的角度来看似乎没问题。 pylint在这件事上是不是太严谨了还是我理解有误?
在我看来,pylint
这一点太过火了。我怀疑在这方面会有太多分歧。我不能代表 pylint 开发人员,但我 猜测 这更多是类型推断的问题,而不是一定被认为是他们的理想行为。
对于引用下划线开头的成员,不同的人可能会告诉你不同的看法。我个人的意见是
- 如果在同一个模块中,公平游戏
- 但是,您仍然应该尽可能地限制这种情况,以避免尽可能地将 class/function 实现捆绑在一起。
- 如果成员属于不同的模块,则不再是公平游戏,应将其视为实现细节。
- 在这里将实现捆绑在一起本质上是危险的,因为对一个实现的更改很容易在没有警告的情况下破坏其他代码。
所以这意味着如果我在 foo.py
中定义了 class Foo
(成员 _member
)并且如果我创建一个子 class Foo
(我们称它为 Bar
)在 bar.py
中,我认为 Bar
不应明确引用 _member
属性。但是,如果您将 Bar
移动到 foo.py
,那么就可以了。事实上,class Baz
(也在 foo.py
中定义)也应该被允许依赖于 Foo
的内部——但这样做最好有充分的理由.
大多数情况下,我不同意将下划线前缀成员视为 "protected"(在 Java 意义上)。我认为它们应该被视为 "implementation details"。 Protected 在 Java 中工作得更好,因为如果你更改实现(例如删除受保护的成员),代码将在编译时失败并让你知道你的 subclass 依赖的受保护成员是不再存在。 Python 没有这样的内置安全措施。
因为下划线前缀名称是 "implementation details",如果它是相同的 class(就像你在问题中描述的情况),那么它是相同的实现,所以(对我来说)允许访问这些成员是显而易见的。我会 # pylint: disable=protected-access
不假思索 :-)。
来自 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
s 代码本身发生了完全相同的情况。 (例如 exceptions.py:338):# pylint: disable=protected-access exc = exc._proxied
所以基本上他们在那种情况下禁用了他们的检查器。
在c++中以下代码有效:
class X { private: int a; protected: int b; public: static void staticMethod(X& x) { x.a = 1; x.b = 1; } };
因此在静态方法中访问 protected/private 成员是有效的。
我会说 pylint
在这种情况下过于敏感。您可以使用评论来禁用那里的检查器。产生警告的原因可能是静态检查器很难实现更复杂的行为。