2011-01-28 91 views
2

我在想,如果有在做这样的事情什么错误(从一个OOP点):将类的所有实例存储在类字段中是不是很糟糕?

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方法。拥有全局变量 而不是类字段会更有意义吗?我可能会在这里使用一个错误的方法,也许这东西甚至不应该是一种方法,但它对我来说很有意义(我是OOP的新手)

+0

如果你决定继续这样做,我建议你使用`self.foobars `或`type(self).foobars`,这样这个类就不会被硬编码。后者需要新式类(即从对象继承的类)。 “ – 2011-01-28 18:09:12

回答

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根本任务收集的方法,而不是个人的任务。你不需要全局变量。

您需要重构。

4

我不认为有任何东西错误与此,但我真的不知道这将是明智的。为什么你需要保持一个全局变量(在所有地方的类中),它保存对所有实例的引用?如果客户只保留一份他的实例清单,客户可以自己轻松实现这一点。总而言之,这看起来有点冒失和不必要,所以我建议你不要这样做。

如果您对自己想要做的更具体,或许我们可以找到更好的解决方案。

+0

”看起来有点冒失和不必要“。我认为你可以从中减少“一点”。 – 2011-01-28 18:00:35

+0

我发布了我使用的代码片段,也许现在更清楚我正在尝试做什么。 – molok 2011-01-28 20:12:45

1

这不是内聚的,也不是非常实用,你想努力让你的对象远离'数据桶'的思维模式。静态对象集合并不会真正获得任何东西,您需要思考为什么需要集合中的所有对象,并考虑创建第二个类,其职责是管理系统中所有Foobar并为其查询。

1

你为什么要这么做?

这段代码有几个问题。首先,您必须注意删除实例 - 每个Foobar实例中总会有一个引用,因此垃圾收集器将永远不会垃圾收集它们。第二个问题是它不适用于copypickle

但除了技术问题,它感觉就像一个错误的设计。对象实例的目的是隐藏状态,并让你看到对方。

0

从OOP的角度来看,它没有任何问题。一个类是元类的一个实例,任何实例都可以存放任何类型的数据。

但是,从效率的角度来看,如果你没有最终清理长期运行的Python程序中的foobars字典,就有可能发生内存泄漏。

0

没有人提到过,如果您稍后从Foobar中派生出一个子类,如果从派生类__init__()调用基类__init__()函数时可能会出现这个潜在问题。具体而言,您是否希望所有子类实例都与基类的实例相同 - 这当然取决于您为什么要这样做。

这是一个可解决的问题,但需要考虑的事情,也许是代码,在基类的前面。

0

我需要多个神社的环境在App Engine应用程序:

class JinjaEnv(object): 
    """ Jinja environment/loader instance per env_name """ 

    _env_lock = threading.Lock() 
    with _env_lock: 
     _jinja_envs = dict()        # instances of this class 

    def __init__(self, env_name): 

     self.jinja_loader = .....       # init jinja loader 
     self.client_cache = memcache.Client() 
     self.jinja_bcc = MemcachedBytecodeCache(self.client_cache, prefix='jinja2/bcc_%s/' % env_name, timeout=3600) 
     self.jinja_env = self.jinja_loader(self.jinja_bcc, env_name) 

    @classmethod 
    def get_env(cls, env_name): 

     with cls._env_lock: 
      if env_name not in cls._jinja_envs: 
       cls._jinja_envs[env_name] = JinjaEnv(env_name) # new env 
      return cls._jinja_envs[env_name].jinja_env 

    @classmethod 
    def flush_env(cls, env_name): 

     with cls._env_lock: 
      if env_name not in cls._jinja_envs: 
       self = cls._jinja_envs[env_name] = JinjaEnv(env_name) # new env 
      else: 
       self = cls._jinja_envs[env_name] 
       self.client_cache.flush_all() 
       self.jinja_env = self.jinja_loader(self.jinja_bcc, env_name) 
      return self.jinja_env 

使用,如:

template = JinjaEnv.get_env('example_env').get_template('example_template') 
相关问题