6

考虑存储云位置的简单天气模型的两个版本:

class cloud:
    def __init__(self, x, y):
        self.x = x
        self.y = y

collection = []
collection.append(cloud(1,2))
collection.append(cloud(4,6))

def update_all_clouds(collection):
    for c in collection:
        cloud.x += 1
        cloud.y += 1

update_all_clouds(collection)

对比

class cloud:
    collection = []
    def __init__(self, x, y)
        self.x = x
        self.y = y
        cloud.collection.append(self)
    @classmethod
    def update_all(cls):
        for c in cloud.collection:
            c.x += 1
            c.y += 1
cloud(1,2)
cloud(4,6)
cloud.update_all()

这基本上已经被惩罚了 ,将一个类的所有实例存储在一个类字段中是不是很糟糕? 但这里强调作用于所有实例的类方法。对于第二种方法提供的最后三行的简单性,没有什么可说的吗?

我知道另一种方法是创建一个类似列表的类,例如,collection 并为该类提供 update_all() 等方法,但对我来说似乎并没有好多少。

4

3 回答 3

3

这个问题可以简单地简化为关于使用全局变量的问题,因为可变的类级成员只是不同命名空间中的全局变量。

所有反对使用全局变量的论点也适用于此。

于 2015-07-09T06:29:26.147 回答
3

一般来说,这很糟糕,是的,原因很简单,列表中的对象几乎永远保持对它们的引用。对对象的引用可以防止它被垃圾收集。因此,您类型的对象基本上永远存在(直到程序终止)并且它们占用的内存永远不会被释放。

当然,如果您对此有非常特殊的需求,并且可以完全控制对象的创建时间,您可以这样做。但总的来说,显式优于隐式,因此最好有一个实际的集合来添加这些元素。该集合甚至可以存在于类型中,因此您可以这样做:

obj = Cloud(…)
Cloud.add(obj)

# or even
obj = Cloud(…).persistInType()

您还可以使用弱引用来避免上述问题,但这是额外的开销,并且管理起来有点复杂。因此,请帮自己一个忙,并手动收集对象。

于 2015-07-09T06:30:52.377 回答
3

考虑到显式优于隐式(参见The Zen of Python),也许最好的方法是拥有两个类:CloudCloudCollection. 这将允许您编写如下代码:

collection = CloudCollection()
collection.add(Cloud(1, 2))
collection.add(Cloud(4, 6))
collection.shift(1, 1)
于 2015-07-09T06:39:02.527 回答