【问题标题】:Static class variable in Python that isn't copied for each instancePython 中的静态类变量,不会为每个实例复制
【发布时间】:2015-07-24 00:05:37
【问题描述】:

我需要一种方法来在 Python 中创建一个只有类才有的静态类变量。我不能为每个实例一遍又一遍地创建这个变量,因为目标类变量将是一个巨大的只读数据结构。每个实例都必须能够通过该类以只读方式访问它,但由于它是大量数据并且将有数千个实例,我无法承受每个实例会再次创建此数据结构的另一个副本。

我找到了this question,但它并没有解决我的问题,因为建议的静态类变量是为每个实例创建的:

>>> class MyClass():
    i = 1
>>> m = MyClass()
>>> m.i
1

换句话说,我正在寻找类似 PHP 中的静态类变量:

<?php
class Foo
{
    public static $my_static = 'foo';
}

$foo = new Foo();
print $foo::$my_static . "\n";     // Accessable throught the class
print $foo->my_static . "\n";      // Undefined "Property" my_static     
?>

这正是我所需要的,静态类变量只为类创建一次,所有实例都可以通过类访问它,但这个静态类变量不会为每个新实例一遍又一遍地创建。是否可以在 Python 中创建这样的静态类变量?

PS:如果我不使用 OOP,我现在有一些解决方法,但如果我能找到一个好的且清晰易读的 OOP 解决方案,那么它在整个项目中会更有意义。

【问题讨论】:

  • 你为什么认为仅仅因为你可以访问它作为m.i它实际上被创建多次?
  • “建议的静态类变量是为每个实例创建的” - 不,这是不正确的。
  • 您可以从一个实例访问它并不意味着它是为每个实例创建的。
  • @renatov if 你在一个实例上分配m.i,此时它会创建一个新实例,隐藏类变量。
  • @renatov 是的,没错。

标签: python oop static-variables


【解决方案1】:

为每个实例创建建议的静态类变量

这是错误的,你可以很容易地证明:

>>> class Test():
    class_attr = []


>>> t1 = Test()
>>> t2 = Test()
>>> t1.class_attr is t2.class_attr
True  # this means that they reference exactly the same object
>>> t1.class_attr.append(1)  # alter via t1
>>> t2.class_attr
[1]  # see the changes via t2

但是,您可以用实例属性覆盖类属性:

>>> t1.class_attr = []
>>> t1.class_attr is t2.class_attr
False

所以如果你需要替换类属性(而不是像append那样就地改变它)你应该通过类而不是实例来这样做(在这种情况下, Test.class_attr = [] 会同时影响t1 t2)。

【讨论】:

  • 您在哪里学习 Python OOP?我读过的所有文档都没有提到你指出的任何东西。你读过什么特别的书或教程吗?
  • @renatov 我无法具体回答,但请注意,这在例如Python官方教程:docs.python.org/2/tutorial/…
【解决方案2】:
class MyClass():
    i = 1

inst = MyClass()

类的所有属性都存储在__dict__ 中。它包含i(除了一堆其他的东西):

>>> MyClass.__dict__
mappingproxy({'__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'__module__': '__main__', '__dict__': <attribute '__dict__' of 'MyClass'
 objects>, 'i': 1, '__doc__': None})

实例没有任何属性:

>>> inst.__dict__
{}

如果在inst.__dict__ 中找不到i,则在MyClass.__dict__ 中继续搜索。尽管它看起来有点像实例有一个属性i,但它实际上只存在于类中。

分配给实例后:

inst.i = 10

这个变化:

>>> inst.__dict__
{'i': 10}

现在,实例有自己的属性了。

【讨论】:

  • 很好的答案,谢谢! Python 中的 OOP 部分让我非常困惑。我将开始使用__dict__ 来检查创建的内容和未创建的内容。
  • @renatov 请注意,您可以使用__slots__ 而不是__dict__,而内置类型也没有,所以这并不总是可能的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-25
  • 2014-02-03
  • 2020-09-29
  • 2012-05-10
相关资源
最近更新 更多