如何在 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.bar
或Foo.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 的方法中访问“静态”类变量?的主要内容,如果未能解决你的问题,请参考以下文章