如何在Python的类方法中访问“静态”类变量?


Answers:


166

代替bar使用self.barFoo.bar。分配给Foo.bar将创建一个静态变量,分配给self.bar将创建一个实例变量。


12
Foo.bar可以工作,但是self.bar创建一个实例变量,而不是静态变量。
bedwyr

47
bedwyr,“ print self.bar”将不会创建任何实例变量(尽管分配给self.bar会)。
康斯坦丁

@Constantin-我没意识到,这是一个有趣的区别。感谢您的纠正:-)
bedwyr

2
但是,如果您不打算有一个ivar,则可以更清楚地使用Foo.classmember。
mk12

2
使用静态变量时,最好从此处读取陷阱:stackoverflow.com/questions/68645/…。@Constantin提供了许多陷阱之一。
Trevor Boyd Smith

84

定义类方法:

class Foo(object):
    bar = 1
    @classmethod
    def bah(cls):    
        print cls.bar

现在,如果bah()必须是实例方法(即可以访问self),则仍可以直接访问类变量。

class Foo(object):
    bar = 1
    def bah(self):    
        print self.bar

3
为什么不只是Foo.bar,而不是self.__class__.bar?
mk12

15
@ Mk12:获得类继承后,“类变量”可以位于基类或子类中。您要参考哪个?取决于您要执行的操作。Foo.bar将始终引用指定类的属性-可以是基类或子类。self.__class__.bar会引用实例是哪种类型的类。
克雷格·麦昆

7
现在,当我们非常了解该语言的细节以至于可以在两个精心调整的用例之间进行区分时,我们已经到达了不幸的地步。这确实取决于您想做什么,但是很多人不会去关注这种微妙之处。
holdenweb 2011年

2
顺便说一句,这是“类变量”的稀有用法。在特定类(这里是Foo)中定义它的情况更为常见。对于某些高级编程情况,这是有用的信息。但是几乎可以肯定不是原来的问题想要什么作为答案(任何需要此答案的人都已经知道如何做Foo.bar)。+1是因为我从中学到了一些东西。
ToolmakerSteve

3
我正在学习何时使用类变量和方法(与实例变量和方法相对)。当您想在实例方法中访问类变量时,是否需要使用self.__class__.bar?我注意到,即使bar是一个类变量而不是实例变量,self.bar仍然有效。
比尔

13

与所有好的示例一样,您已经简化了实际要执行的操作。这很好,但是值得注意的是,在类变量和实例变量之间,python具有很大的灵活性。方法也可以这样说。有关各种可能性的建议,我建议阅读MichaelFötsch的新型课程介绍,尤其是第2至6节。

入门时需要记住很多事情的一件事是python不是java。 不只是陈词滥调。在Java中,整个类都会被编译,使名称空间解析真正简单:方法外(在任何地方)声明的任何变量都是实例(或类,如果是静态的话)变量,并且可以在方法内隐式访问。

使用python的主要经验法则是,按顺序搜索三个名称空间以查找变量:

  1. 功能/方法
  2. 当前模块
  3. 内建

{begin pedagogy}

有一些例外。我主要想到的是,在加载类定义时,该类定义是其自己的隐式命名空间。但这仅在模块被加载时才持续,并且在方法内时将被完全忽略。从而:

>>> class A(object):
        foo = 'foo'
        bar = foo


>>> A.foo
'foo'
>>> A.bar
'foo'

但:

>>> class B(object):
        foo = 'foo'
        def get_foo():
            return foo
        bar = get_foo()



Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    class B(object):
  File "<pyshell#11>", line 5, in B
    bar = get_foo()
  File "<pyshell#11>", line 4, in get_foo
    return foo
NameError: global name 'foo' is not defined

{end pedagogy}

最后,要记住的是,您确实有权访问要访问的任何变量,但可能不是隐式的。如果您的目标简单明了,那么选择Foo.bar或self.bar可能就足够了。如果您的示例变得越来越复杂,或者您想做一些继承之类的事情(可以继承静态/类方法!),或者在类本身中引用类名的想法对您来说是错误的,请查看我链接的简介。


IIRC,从技术上讲,搜索了3(+)个名称空间-局部函数,模块/全局和内建函数。嵌套作用域意味着可以搜索多个本地作用域,但这是例外情况之一。(...)
杰夫·香农

另外,我会谨慎地说“主模块”,因为搜索的是函数的包含模块,而不是模块...并且从实例ref查找属性是另一回事,但是此答案确实说明了原因您需要实例/类引用。
杰夫·香农(


-2
class Foo(object):    
    bar = 1

    def bah(object_reference):
        object_reference.var = Foo.bar
        return object_reference.var


f = Foo() 
print 'var=', f.bah()

4
尽管这段代码可以解决问题,但包括解释如何以及为什么解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加说明,并指出适用的限制和假设。来自评论
double-beep
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.