【问题标题】:How can I access "static" class variables within methods in Python?如何在 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 oop static-variables


【解决方案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,经验法则是按顺序在三个命名空间中搜索变量:

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

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

    【讨论】:

    • Foo.bar 可以工作,但 self.bar 创建一个实例变量,而不是静态变量。
    • bedwyr, "print self.bar" 不会创建任何实例变量(尽管分配给 self.bar 会)。
    • @Constantin -- 我没有意识到,这是一个有趣的区别。感谢您的更正:-)
    • 但是如果你不打算有一个 ivar,使用 Foo.classmember 会更清楚。
    • 使用静态变量时,最好从这里阅读问题:stackoverflow.com/questions/68645/…。 @Constantin 给出了许多陷阱之一。
    猜你喜欢
    • 1970-01-01
    • 2017-01-13
    • 2015-02-18
    • 2011-03-05
    • 2015-07-22
    • 2012-06-29
    • 2014-04-01
    • 2013-09-08
    • 2012-07-17
    相关资源
    最近更新 更多