我有这个类:
class ReallyLongClassName:
static_var = 5
def instance_method(self):
ReallyLongClassName.static_var += 1
有没有一种方法可以使用self变量访问静态变量?
我更愿意像这样做class(self).static_var += 1
,因为长名称不可读。
我有这个类:
class ReallyLongClassName:
static_var = 5
def instance_method(self):
ReallyLongClassName.static_var += 1
有没有一种方法可以使用self变量访问静态变量?
我更愿意像这样做class(self).static_var += 1
,因为长名称不可读。
self.__class__.classAttr
。这适用于旧式和新式类。答案是“是的,但是…”
最好的方法是实际尝试一下:
>>> class RLCN:
... static_var = 5
... def method1(self):
... RLCN.static_var += 1
... def method2(self):
... self.static_var += 1
>>> rlcn = RLCN()
>>> RLCN.static_var, rlcn.static_var
(5, 5)
>>> rlcn.static_var
5
>>> rlcn.method1()
>>> RLCN.static_var, rlcn.static_var
(6, 6)
>>> rlcn.method2()
>>> RLCN.static_var, rlcn.static_var
(6, 7)
发生了什么?
好的,通过self访问类属性完全没问题。如果没有同名实例属性,您将获得类属性。
但是分配给它将使用同名的新实例属性隐藏类属性。这可能不是您想要的。
请注意,这意味着您可以将类属性用作实例属性的“默认值”或“初始值”。但我不确定这样做是否非常符合Pythonic的风格;实际上正在发生什么,以及初学者(尤其是从C++11或Java等语言转换而来的人)所认为的情况是非常不同的。
(当涉及到描述符(例如方法或@property
)时,情况会稍微复杂一些,但让我们暂且忽略这一点;在您讨论的简单情况下,这并不相关。)
我更愿意像class(self).static_var += 1这样做,因为长名称难以阅读。
您可以这样做,只需要拼写正确:type
是返回任何对象类型的函数。所以:
type(self).static_var += 1
这种方法的优点是具有动态性(例如,当您具有多重继承并且不知道一个 @property
来自哪一边时,您可能不想显式列出类名,基本上出于与使用 super()
相同的原因,您要调用基类方法而不是显式调用它)。
这种方法的缺点是在 Python 2.x 中无法用于旧样式类,但您不应该使用那些类。特别是在需要类属性的类中,因为这些恰好是您通常随后要添加 @classmethod
、@property
等内容的类型,并且这些都不适用于旧样式类(以及许多其他内容)。如果您真的需要以某种方式透明地处理旧样式和新样式类,self.__class__
适用于旧样式类。我不确定它是否保证适用于新样式类;文档说 type(object)
的返回值“通常与 object.__class__
返回的对象相同”,但没有说明在什么条件下,“通常”是不正确的。在 3.x 中,它还记录为一个“由实现添加”的“几个对象类型”的特殊属性。实际上,我不知道在 3.x 中它们不同的任何情况,在 2.x 中,它们不同的最突出情况是旧样式类。
type
,且所有相关的好处也变得无关紧要,因为在旧式类上,super
、@property
、多重继承等都不起作用。但是解决这个问题很简单:不要使用旧式类。但我会添加一条注释来说明这个问题。 - abarnertglobal
或nonlocal
语句)之间的相似之处,或者这样做只会潜在地让人们感到困惑? - abarnertmethod2
中发生了什么的解释是很困难的。 - bigh_29
type(self)
更好吗? - Alexeyself.__class__
非常不符合 Python 风格,如果你不想硬编码类名,应该使用type(self)
来代替(如 https://dev59.com/ll8e5IYBdhLWcg3wnbRj#25577642 所示)。唯一需要小心的情况是在继承类中访问超类属性时,属性名以__
开头(但不以__
结尾),因为名称修饰会困扰你。无论如何,使用硬编码类名是最安全的方法。 - 0xc0de