Python类变量初始化

7 投票
1 回答
18828 浏览
提问于 2025-04-17 08:23

我想把一些关于类的信息存储为类的(静态)变量。但是,我搞不清楚这些变量是怎么初始化的。这里有一个简单的例子:

class A(object):
    clsVar = 'a'
    @classmethod
    def clsMeth(cls):
        print 'changing clsVar'
        cls.clsVar = 'b'
    A.clsMeth()
# prints 'changing clsVar'

print A.clsVar    # prints 'a'
A.clsVar = 'b'
print A.clsVar    # prints 'b'

既然这个函数被调用了(因为打印语句有效),为什么类变量没有保持更改呢?如果我不想等到类定义完成后再做这些,难道就必须使用一个 metaclass 吗?

[具体来说,我想让 clsMeth 成为一个装饰器,并且让类变量成为一个包含所有被装饰函数的列表。我猜这不是实现这个目标的正确方法,所以我已经放弃了,但我还是很好奇。]

编辑:正如很多人指出的,上面的代码是无法运行的。我是在一个 IPython 会话中运行的,在那里调用 A.clsMeth() 会引用 A 的一个之前版本并执行。使用解释型语言就是有这样的风险。我最后选择了类似这样的方式:

outsideDict = {}
def outsideDec(func):
    outsideDict[func.__name__] = func

class A(object):
    @outsideDec
    def someMethod(self):
        print 'ID %s' % id(self)

    def otherMethod(self):
        print 'other'

print outsideDict
one, two = A(), A()
outsideDict['someMethod'](one)
outsideDict['someMethod'](two)

也许这应该是另一个问题,但当 outsideDec 被运行时,有没有办法知道它的参数属于哪个类?或者在 Python 中有没有更好的方法来进行这样的自省?我意识到我偏离了主题,所以我会接受下面的答案并做更多的研究。谢谢大家!

1 个回答

6

在定义 A 的时候,调用 A.clsMeth() 是不会执行的,因为那个时候 A 还不存在:

>>> class A(object):
...     clsVar = 'a'
...     @classmethod
...     def clsMeth(cls):
...         print 'changing clsVar'
...         cls.clsVar = 'b'
...     A.clsMeth()
... 
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "<stdin>", line 7, in A
NameError: name 'A' is not defined

如果 A 之前已经定义过,代码可能看起来能正常工作(比如你在 REPL 里测试的时候),但调用 A.clsMeth 实际上是针对旧的类进行的,而这个旧的类会被新的类覆盖。

不过,我们可以把这个调用放在定义之后,这样就能得到你想要的结果:

>>> class A(object):
...     clsVar = 'a'
...     @classmethod
...     def clsMeth(cls):
...         print 'changing clsVar'
...         cls.clsVar = 'b'
...
>>> A.clsMeth()
changing clsVar
>>> A.clsVar
'b'

当然,正如 fabianhrj 提到的,你也可以把它放在构造函数里,但这样的话,直到你创建一个实例的时候,它才会被调用。

撰写回答