Pythonic方式初始化(复杂)静态数据成员

20 投票
3 回答
16468 浏览
提问于 2025-04-15 11:38

我有一个类,里面有一个复杂的数据成员,我想让它保持“静态”。我想用一个函数来初始化它,只需要初始化一次。像这样的做法在Python中算不算好呢:

def generate_data():
    ... do some analysis and return complex object e.g. list ...

class Coo:
    data_member = generate_data()
    ... rest of class code ...

这个函数 generate_data 需要花费很长时间才能完成,并且返回的数据在程序运行期间是保持不变的。我不想在每次创建类 Coo 的实例时都运行这个函数。

另外,我想确认一下,只要我在 __init__ 方法中不对 data_member 进行赋值,它就会保持“静态”状态,对吧?如果 Coo 类中的某个方法往 data_member(假设它是一个列表)添加了一些值,这个添加的值会对其他实例可用吗?

谢谢

3 个回答

6

这段代码 data_member = generate_data() 只会执行一次,发生在 class coo: ... 这段代码被运行的时候。通常情况下,类的定义是在模块的层级上进行的,也就是说,当你导入这个模块时,这段代码就会被执行。所以,data_member = generate_data() 只会在你第一次导入包含 coo 类的模块时执行一次。

所有的 coo 类的实例都会共享这个 data_member,你可以通过写 coo.data_member 来访问它。对 coo.data_member 的任何修改,所有的 coo 实例都能立刻看到。每个实例也可以有自己的 data_member 属性。你可以通过写 self.data_member = ... 来设置这个属性,这样它只对那个特定的实例可见。不过,那个“静态”的 data_member 仍然可以通过 coo.data_member 来访问。

13

正如其他人所说,你说得对——我再补充一点需要注意的:如果一个实例修改了对象的 coo.data_member 本身,比如说

self.data_member.append('foo')

那么其他实例也能看到这个修改。但是如果你这样做

self.data_member = new_object

那么就会创建一个新的 实例 成员,这个新的成员会覆盖掉类成员,只对这个实例可见,其他实例看不到。这个区别并不总是容易发现,比如 self.data_member += 'foo'self.data_member = self.data_member + 'foo' 之间的差别。

为了避免这种情况,你最好总是通过 coo.data_member 来引用这个对象,而不是通过 self

18

你说得完全正确。data_member 只会被创建一次,并且对所有的 coo 实例都是可用的。如果任何一个实例修改了它,其他所有实例都能看到这个修改。

下面是一个例子,展示了这些内容,最后会显示它的输出:

def generate_data():
    print "Generating"
    return [1,2,3]

class coo:
    data_member = generate_data()
    def modify(self):
        self.data_member.append(4)

    def display(self):
        print self.data_member

x = coo()
y = coo()
y.modify()
x.display()

# Output:
# Generating
# [1, 2, 3, 4]

撰写回答