在一个类变量中收集所有实例总是不好的吗?

Posted

技术标签:

【中文标题】在一个类变量中收集所有实例总是不好的吗?【英文标题】:Is it always bad to collect all instances in a class variable? 【发布时间】:2015-07-09 06:20:34 【问题描述】:

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

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()

这里基本上已经被惩罚了 Is it bad to store all instances of a class in a class field? 但这里强调作用于所有实例的类方法。 第二种方法提供的最后三行的简单性没有什么可说的吗?

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

【问题讨论】:

【参考方案1】:

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

当然,如果您对此有非常具体的需求,并且可以完全控制对象的创建时间,那么您可以这样做。但总的来说explicit is better than implicit,所以最好有一个实际的集合来添加这些元素。该集合甚至可以存在于类型中,因此您可以这样做:

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

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

您也可以使用weak references 来避免上述问题,但这是额外的开销,并且管理起来有点复杂。所以请帮自己一个忙,手动收集物品。

【讨论】:

将在 init 上有一个可选参数add_to_collection=False,以便根据该变量检查将对象添加到集合中使事情变得明确? 我想这可行。但是您还应该添加一些功能来处理对象,将其从列表中删除。 我发布的代码是一个简化。该系列不断被淘汰@poke【参考方案2】:

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

collection = CloudCollection()
collection.add(Cloud(1, 2))
collection.add(Cloud(4, 6))
collection.shift(1, 1)

【讨论】:

根据 “简单胜于复杂”“特殊情况不足以打破规则”,您只需不过在那里使用普通列表;) 在我看来,只要我们可以将“集合”视为具有自己的“操纵器”的独立实体,就可以为其使用专用类。我并不是说这一定是 OP 的情况。 最终做了“class collection(list)”和“clouds = collection() etc”【参考方案3】:

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

所有arguments against using global variables 也适用于此。

【讨论】:

这实际上比仅仅一个全局变量更糟糕。如果有人调用Cloud.addObject(cloudObj),它将“只是”一个全局变量,但这里的对象是自动添加的。

以上是关于在一个类变量中收集所有实例总是不好的吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 VBA 中初始化无限数量的类:使用变量来命名类的实例

在 C++ 中使用指针总是不好的吗?

从元类设置实例变量

在Java程序设计中实例变量和类变量有啥区别?

对 for 构造中的第二个表达式使用 size() 总是不好的吗?

python类变量和实例变量的区别