我可以从实例访问一个类变量吗?

55

我有这个类:

class ReallyLongClassName:
    
    static_var = 5

    def instance_method(self):
        ReallyLongClassName.static_var += 1

有没有一种方法可以使用self变量访问静态变量?

我更愿意像这样做class(self).static_var += 1,因为长名称不可读。

2个回答

77
使用 self.__class__.classAttr。这适用于旧式和新式类。

2
这种方式比type(self)更好吗? - Alexey
@Alexey,请查看 https://dev59.com/ll8e5IYBdhLWcg3wnbRj#25577642 上的评论。 - Judah Meek
18
请不要被投票数所说服,self.__class__ 非常不符合 Python 风格,如果你不想硬编码类名,应该使用 type(self) 来代替(如 https://dev59.com/ll8e5IYBdhLWcg3wnbRj#25577642 所示)。唯一需要小心的情况是在继承类中访问超类属性时,属性名以 __ 开头(但不以 __ 结尾),因为名称修饰会困扰你。无论如何,使用硬编码类名是最安全的方法。 - 0xc0de

73

答案是“是的,但是…”

最好的方法是实际尝试一下:

>>> 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 中,它们不同的最突出情况是旧样式类。


@AntonSavin:不,它在Python 2中完美运行。在Python 2.7.2中此处查看。 - abarnert
3
如果您使用旧式类,则确实无法使用 type,且所有相关的好处也变得无关紧要,因为在旧式类上,super@property、多重继承等都不起作用。但是解决这个问题很简单:不要使用旧式类。但我会添加一条注释来说明这个问题。 - abarnert
重新阅读这段内容,我在想是否值得指出self与类属性之间的相似之处,以及本地变量与全局/闭包变量(没有globalnonlocal语句)之间的相似之处,或者这样做只会潜在地让人们感到困惑? - abarnert
1
好的解释。唯一的缺点是,如果在创建类之后更改类名,则类本身中对旧类名的所有引用都需要更改... - repzero
1
有没有一个被接受的名称,可以将类变量提升为实例变量进行赋值?通过谷歌查找method2中发生了什么的解释是很困难的。 - bigh_29
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接