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

Posted

技术标签:

【中文标题】如何在 Python 的方法中访问“静态”类变量?【英文标题】:How can I access "static" class variables within methods in Python? 【发布时间】:2010-10-16 23:34:06 【问题描述】:

如果我有以下代码:

class Foo(object):
    bar = 1

    def bah(self):
        print(bar)
        
f = Foo()
f.bah()

它抱怨

NameError:未定义全局名称“bar”

如何在方法bah 中访问类/静态变量bar

【问题讨论】:

更多关于 Python 和静态的信息可以在这里找到:***.com/questions/68645/python-static-variable 【参考方案1】:

bar 是您的静态变量,您可以使用Foo.bar 访问它。

基本上,您需要使用类名来限定静态变量。

【讨论】:

考虑添加更多信息以扩展您的答案,或考虑编辑其他答案以添加此详细信息。【参考方案2】:
class Foo(object):
     bar = 1
     def bah(self):
         print Foo.bar

f = Foo() 
f.bah()

【讨论】:

【参考方案3】:

定义类方法:

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

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

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

【讨论】:

为什么不只是 Foo.bar,而不是 self.__class__.bar? @Mk12:当你有类继承时,“类变量”可以在基类或子类中。你想参考哪个?取决于你想要做什么。 Foo.bar 将始终引用指定类的属性——它可能是基类或子类。 self.__class__.bar 将引用实例所属的任何类。 现在我们已经到了不幸的地步,因为我们非常了解语言的细节,以至于我们可以区分两个精细协调的用例。这确实取决于你想做什么,但很多人不会注意这些微妙之处。 顺便说一句,这是“类变量”的罕见用法。更常见的是在特定的类中定义它,这里是 Foo。这对于一些高级编程情况很有用。但几乎可以肯定不是原始问题想要的答案(任何需要这个答案的人都已经知道如何做 Foo.bar)。 +1,因为我从中学到了一些东西。 我正在学习何时使用类变量和方法(而不是实例变量和方法)。当你想在实例方法中访问一个类变量时,是否需要使用self.__class__.bar?我注意到即使 bar 是类变量而不是实例变量, self.bar 也可以工作。【参考方案4】:

与所有好的示例一样,您已经简化了您实际尝试做的事情。这很好,但值得注意的是,当涉及到类与实例变量时,python 具有很大的灵活性。方法也是如此。要获得一个很好的可能性列表,我建议阅读Michael Fötsch' new-style classes introduction,尤其是第 2 到第 6 节。

在入门时需要花费大量工作才能记住的一点是 python 不是 java。 不仅仅是陈词滥调。在 java 中,整个类都被编译,使得命名空间解析变得非常简单:在方法之外(任何地方)声明的任何变量都是实例(或者,如果是静态,则为类)变量,并且可以在方法内隐式访问。

对于 python,经验法则是按顺序在三个命名空间中搜索变量:

    函数/方法 当前模块 内建

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(+) 个命名空间——函数本地、模块/全局和内置。嵌套范围意味着可以搜索多个本地范围,但这是例外情况之一。 (...) 另外,我会小心地说“主模块”,因为搜索的是函数的包含模块,而不是 main 模块......并查找属性从实例引用是另一回事,但这个答案确实解释了为什么你需要实例/类引用。【参考方案5】:

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

【讨论】:

Foo.bar 可以工作,但 self.bar 创建一个实例变量,而不是静态变量。 bedwyr, "print self.bar" 不会创建任何实例变量(尽管分配给 self.bar 会)。 @Constantin -- 我没有意识到,这是一个有趣的区别。感谢您的更正:-) 但是如果你不打算有一个 ivar,使用 Foo.classmember 会更清楚。 使用静态变量时,最好从这里阅读问题:***.com/questions/68645/…。 @Constantin 给出了许多陷阱之一。

以上是关于如何在 Python 的方法中访问“静态”类变量?的主要内容,如果未能解决你的问题,请参考以下文章

Python-面向对象高级语法之静态方法类方法

python 面向对象(成员,静态,类)的(变量,方法)区别

Python 面向对象

如何在静态方法中访问类变量

python静态方法类方法属性方法

python 为啥要使用静态方法