2011-01-28 70 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') 
相關問題