2010-03-11 5 views
1

Voici mon problème. J'ai créé une classe readonly assez lourde faisant beaucoup d'appels de base de données avec une méthode "d'usine" statique. Le but de cette méthode est d'éviter de détruire la base de données en regardant dans un pool d'objets déjà créés si une instance identique du même objet (même type, mêmes paramètres init) existe déjà.Comment créer des instances d'une classe à partir d'une méthode statique?

Si quelque chose a été trouvé, la méthode va juste le retourner. Aucun problème. Mais sinon, comment puis-je créer une instance de l'objet, d'une manière qui fonctionne avec l'héritage?

>>> class A(Object): 
>>>  @classmethod 
>>>  def get_cached_obj(self, some_identifier): 
>>>   # Should do something like `return A(idenfier)`, but in a way that works 

>>> class B(A): 
>>>  pass 

>>> A.get_cached_obj('foo') # Should do the same as A('foo') 
>>> A().get_cached_obj('foo') # Should do the same as A('foo') 
>>> B.get_cached_obj('bar') # Should do the same as B('bar') 
>>> B().get_cached_obj('bar') # Should do the same as B('bar') 

Merci.

+1

Pourquoi si complexe? Pourquoi ne pas simplement 'getInstance (A, 'foo')' ou 'getInstance (b, 'bar')'? –

+0

La classe réelle est un peu plus compliquée que celle de l'exemple. Cette partie était juste celle qui manquait, en fait :) – Pierre

Répondre

4
import weakref 

class A(object): 
    _get_obj_cache = weakref.WeakValueDictionary() 
    @classmethod 
    def get_obj(cls, identifier): 
    cache = cls._get_obj_cache 
    obj = cache.get((cls, identifier)) 
    if obj is None: 
     obj = cache[(cls, identifier)] = cls(identifier) 
    return obj 

class B(A): 
    pass 

Parce qu'un WeakValueDictionary est utilisé, les objets mis en cache tant restent que vous avez une autre référence à eux, et vous pouvez appeler SomeClass.get_obj (identifiant) autant de fois que vous le souhaitez pour obtenir ce même objet . Si je vous ai bien compris, c'est le cls(identifier) qui va toucher la base de données et ce que vous voulez appeler moins fréquemment, puisque vous savez que les objets sont immuables.

Si vous souhaitez conserver des objets dans le cache même s'ils ne sont plus référencés ailleurs, remplacez le WeakValueDictionary par un dict normal.

Cela nécessite que identificateur est approprié pour une clé dict, et si c'est une chaîne comme vous avez dans votre exemple de code, alors il est.

+0

Tkank vous tant. Exactement ce que je cherchais. Tu m'as bien compris :) – Pierre

1

Une approche habituelle est la suivante.

class SomeClass(object): 
    # Something that is precious and needs to be pooled. 

class SomeClassPool(object): 
    def __init__(self): 
     self.pool= [ SomeClass() ] 
    def getInstance(self): 
     if len(self.pool) == 0: 
      self.pool.append(SomeClass()) 
      # maybe allocate several, depends on the costs 
     return self.pool.pop() 
    def release(self, anInstance): 
     self.pool.append(anInstance) 

Nous séparons le pool des objets en cours de regroupement. Ils n'ont rien à faire ensemble.

Vous pouvez sous-classer les objets en cours de regroupement.

Vous pouvez - indépendamment - modifier les stratégies de regroupement sans casser ou réessayer les objets en cours de regroupement.

+0

Oui, merci. En fait, ce que je veux faire n'est pas vraiment un pool commun. Je ne veux pas avoir beaucoup de cours qui font la même chose et en prendre un au besoin. Je n'ai qu'une instance pour un paramètre init donné (comme un ID utilisateur, par exemple), et je veux renvoyer l'instance correcte à chaque fois, sans la retirer du pool (la classe supporte les accès concurrents de manière transparente, car elle est en lecture seule). .) – Pierre

+0

"Je veux renvoyer l'instance correcte à chaque fois, sans la retirer du pool". Vous voulez dire que vous voulez un dictionnaire d'objets? –

0

Expansion sur le commentaire de S. Lott:

« Je veux retourner l'instance correcte à chaque fois, sans le retirer de la piscine ». Voulez-vous dire que vous voulez un dictionnaire d'objets? -S.Lott

the_cache = {} 

def get_obj(cls, identifier): 
    key = (cls, identifier) 
    if key not in the_cache: 
     the_cache[key] = cls(identifier) 
    return the_cache[key] 

ou

def get_obj(cls, identifier): 
    key = (cls, identifier) 
    try: 
     return the_cache[key] 
    except KeyError: 
     the_cache[key] = cls(identifier) 
     return the_cache[key] 
Questions connexes