将所有类实例存储在类字段中是否不好?

2 投票
7 回答
3509 浏览
提问于 2025-04-16 10:48

我在想,从面向对象编程的角度来看,这样做是否有什么问题:

class Foobar:
    foobars = {}
    def __init__(self, name, something):
        self.name = name
        self.something = something

        Foobar.foobars[name] = self

Foobar('first', 42)
Foobar('second', 77)

for name in Foobar.foobars:
    print name, Foobar.foobars[name]

编辑: 这是我现在正在使用的实际代码

from threading import Event
class Task:
    ADDED, WAITING_FOR_DEPS, READY, IN_EXECUTION, DONE = range(5)
    tasks = {}
    def __init__(self, name, dep_names, job, ins, outs, uptodate, where):
        self.name = name
        self.dep_names = [dep_names] if isinstance(dep_names, str) else dep_names
        self.job = job
        self.where = where
        self.done = Event()
        self.status = Task.ADDED
        self.jobs = []
        # other stuff...
        Task.tasks[name] = self
    def set_done(self):
        self.done.set()
        self.status = Task.DONE
    def wait_for_deps(self):
        self.status = Task.WAITING_FOR_DEPS
        for dep_name in self.dep_names:
            Task.tasks[dep_name].done.wait()
        self.status = Task.READY
    def add_jobs_to_queues(self):
        jobs = self.jobs
        # a lot of stuff I trimmed here
        for w in self.where: Queue.queues[w].put(jobs)
        self.status = Task.IN_EXECUTION
    def wait_for_jobs(self):
        for j in self.jobs: j.wait()
    #[...]

如你所见,我需要在wait_for_deps方法中访问一个包含所有实例的字典。用一个全局变量会不会更合理,而不是用类的字段?我可能在这里用错了方法,也许这些东西根本不应该放在一个方法里,但对我来说这样做是有道理的(我刚接触面向对象编程)

7 个回答

1

你为什么想这么做呢?

这段代码有几个问题。第一个问题是你需要手动删除实例——每个 Foobar 实例都会在 Foobar.foobars 中留下一个引用,这样垃圾回收器就无法清理它们。第二个问题是,这段代码在使用 copypickle 时会出问题。

不过,除了这些技术问题,这种设计感觉也不太对。对象实例的目的是隐藏状态,而你却让它们彼此可见。

4

我觉得这样做没有什么错误,但我真的看不出这样做有什么意义。为什么你需要在类里面保持一个全局变量,来存放所有实例的引用呢?客户自己完全可以简单地维护一个自己的实例列表。总的来说,这看起来有点像是变通的做法,而且也没必要,所以我建议你不要这样做。

如果你能更具体地说说你想要做什么,也许我们能找到更好的解决办法。

9

是的,这样做不好。它把一个实例和一堆实例搞混了。

集合是一回事。

被收集的实例之间没有关系。

另外,类级别的变量更新会让我们一些人感到困惑。没错,我们最终能理解发生了什么,但大家通常的期望是,状态的变化应该是针对对象的,而不是类。


 class Foobar_Collection( dict ):
     def __init__( self, *arg, **kw ):
         super( Foobar_Collection, self ).__init__( *arg, **kw ):
     def foobar( self, *arg, **kw ):
         fb= Foobar( *arg, **kw )
         self[fb.name]= fb
         return fb

 class Foobar( object ):
     def __init__( self, name, something )
         self.name= name
         self.something= something

fc= Foobar_Collection()
fc.foobar( 'first', 42 )
fc.foobar( 'second', 77 ) 

for name in fc:
    print name, fc[name]

这更常见一些。


在你的例子中,wait_for_deps 只是任务集合中的一个方法,而不是单个任务的方法。你不需要全局变量。

你需要重构一下代码。

撰写回答