【问题标题】:Python - Static Class VariablesPython - 静态类变量
【发布时间】:2017-04-03 14:08:00
【问题描述】:

我来自 C++ 背景,并且经常使用静态变量来减少必须初始化变量的时间(特别是如果初始化需要很长时间)。因此,从 StackOverflow 上的其他帖子中,人们建议使用静态类变量,如下所示:

class MyClass(object):

    StaticList1 = [...] # Very large list
    StaticList2 = [...] # Very large list

如果在整个程序执行过程中至少存在 1 个 MyClass 实例并且列表只创建一次,这很好。但是,如果在执行的某个阶段没有 MyClass 的实例,Python 似乎会删除静态列表(我假设是因为引用计数器下降到 0)。

所以我的问题是,是否有任何简单的方法不使用外部模块来初始化 StaticList1 和 StaticList2 一次(第一次使用它们)并且即使在程序存在之前没有 MyClass 实例也永远不要删除它们(或您手动删除列表)?

编辑:

也许我把这个问题简单化了。我在做什么:

class MyClass(object):

    StaticList = None

    def __init__(self, info):
        if self.StaticList == None:
            print "Initializing ..."
            self.StaticList = []
            # Computationally expensive task to add elements to self.StaticList, depending on the value of parameter info

    def data(self):
        return self.StaticList

我从另一个脚本导入模块并有这样的循环:

import myclass
for i in range(10000):
    m = myclass.MyClass(i)
    d = m.data()
    # Do something with d.

静态列表的初始化大约需要 200 - 300 毫秒,并且在循环的每次迭代中执行,因此循环需要很长时间才能完成。

【问题讨论】:

  • 您可以利用模块是单例的这一事实,因此如果您创建这些模块级成员,只要模块被导入,它们就会一直存在并且只会存在一次。
  • 这听起来不对,我不希望这些列表会去任何地方。你是说你打电话给MyClass.StaticList1 ...,你得到一个错误?你遇到了什么错误?
  • * 但是,如果在执行的某个阶段没有 MyClass 的实例,Python 似乎删除了静态列表* AFAIK,这是错误的。该类将独立于该类的对象而存在,并且在类级别定义的所有属性将继续通过该类存在。你能举例说明你的问题吗?
  • 如果每次调用构造函数/__init__ 时都会清除并重新计算静态变量。然后我不明白为什么它在 C++ 或 Python 中应该是静态的,它只是需要在循环的每次迭代中完成的工作。可能大部分工作都发生在# Computationally expensive task... 线上,而你是如何做到的,你没有展示出来。

标签: python class static


【解决方案1】:

虽然您的类确实有一个名为 StaticList 的静态字段,但由于您使用的是 self 限定符,您实际上是在初始化和使用同名的 实例字段。我认为如果您使用 MyClass.StaticList 来初始化和访问它,您的代码将可以正常工作。

通常,通过 Python 的名称查找,您可以通过实例访问类字段,就好像它是该实例上的实例字段(例如,self.StaticList只要您没有' t 实际上在该实例上设置了一个同名的实例字段。从那一刻起,实例字段将隐藏类字段(即,self.StaticList 将找到您的新值,而 MyClass.StaticList 仍将引用您的类值)。

作为一个来自解释器的新鲜示例:

>>> class A(object):
...  v=2      # static initialization
...
>>> A.v
2
>>> a=A()     # get an instance, and
>>> a.v       # get the static value via the instance:
2
>>> a.v = 7   # but now set 'v' on the instance, and ...
>>> a.v       # we will get the instance field's value:
7
>>> A.v       # the static value is still the old:
2
>>> b=A()     # and other instances of the class ...
>>> b.v       # will use the same old static value:
2

实例变量a.v 最初等于A.v,但通过显式设置a.v=7,您将在该实例中“分离”它们。

虽然这意味着原则上您可以使用静态类字段 MyClass.Values 以及同名的实例字段 xyz.Values,但通常不鼓励这样做这种混乱。

作为单独的注释,您可以考虑将 data 方法注释为 @staticmethod(并在移动中删除 self 参数)并将其称为 MyClass.data() 以使事实更清楚每次调用都返回相同的列表实例。

【讨论】:

  • 如果不是因为这个,这听起来很合乎逻辑:我一直在将 self.StaticVar 用于一堆其他类,其中静态变量直接在声明而不是构造函数中初始化。如果我然后在类中的某处打印出 self.StaticVar,则打印 var 的值。因此,在这种情况下,似乎 MyClass.StaticVar 与 self.StaticVar 相同
  • 我已经扩展了答案的逻辑来解决这方面的问题。 :)
猜你喜欢
  • 1970-01-01
  • 2012-09-14
  • 1970-01-01
  • 1970-01-01
  • 2021-11-17
  • 2012-07-03
  • 2013-09-08
  • 2018-06-22
相关资源
最近更新 更多