Python类变量初始化

7

我希望将一些关于类的信息存储为类(静态)变量。然而,我无法弄清楚这些变量是如何初始化的。以下是一个基本的、愚蠢的例子:

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'

自函数被调用(因为打印语句可以工作),为什么类变量没有保持更改?如果我不想在类定义完成后执行更改,我是否需要使用元类?
[具体而言,我想要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中有更好的进行内省的方法吗?我认识到我偏离了主题,所以我会接受下面的答案并进行更多的研究。谢谢大家!

当调用A.clsMeth时,我得到的是一个错误,因为A未定义。也许你正在使用解释器,并且你有一个旧的A定义? - jcollado
你如何运行这个示例?由于语法不正确,它无法工作。A.clsMth()不能像这样放在类定义内部。 - gecco
@gecco:当然可以;语法是正确的。正如jcollado所提到的,当调用A.clsMeth()时,由于尚未对A进行赋值,它将导致运行时错误,但你是可以这样做的。 - Glenn Maynard
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所指出的那样,你也可以将它放在构造函数中,但直到你创建一个实例时,它才会被调用。

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