Как создать экземпляры класса из статического метода? - PullRequest
2 голосов
/ 11 марта 2010

Вот моя проблема. Я создал довольно тяжелый класс только для чтения, который выполняет много обращений к базе данных со статическим «фабричным» методом. Цель этого метода - избежать уничтожения базы данных, просматривая пул уже созданных объектов, если идентичный экземпляр того же объекта (того же типа, с теми же параметрами инициализации) уже существует.

Если что-то было найдено, метод просто вернет это. Нет проблем. Но если нет, как я могу создать экземпляр объекта способом, который работает с наследованием?

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

Спасибо.

Ответы [ 3 ]

4 голосов
/ 11 марта 2010
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

Поскольку используется WeakValueDictionary, объекты будут сохраняться в кэше, пока у вас есть любая другая ссылка на них, и вы можете вызывать SomeClass.get_obj (идентификатор) столько раз, сколько захотите, чтобы получить тот же объект. Если я вас правильно понял, это cls(identifier), который попадет в базу данных и то, что вы хотите вызывать реже, поскольку вы знаете, что объекты неизменны.

Если вы хотите сохранить объекты в кэше, даже если на них больше нет ссылок в другом месте, измените WeakValueDictionary на обычный dict.

Для этого требуется, чтобы идентификатор подходил для ключа dict, и если это строка, как у вас в коде примера, то это так.

1 голос
/ 11 марта 2010

Один обычный подход - это.

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 )

Мы отделяем пул от объединенных объектов. Они не имеют ничего общего друг с другом.

Вы можете создавать подклассы объединенных объектов, сколько хотите.

Вы можете - независимо - изменять стратегии объединения без нарушения или повторного тестирования объединенных объектов.

0 голосов
/ 11 марта 2010

Расширение комментария С. Лотта:

"Я хочу вернуть правильный экземпляр каждый раз, не удаляя его из бассейн ". Вы имеете в виду, что вы хотите словарь объектов? -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]

или

def get_obj(cls, identifier):
    key = (cls, identifier)
    try:
        return the_cache[key]
    except KeyError:
        the_cache[key] = cls(identifier)
        return the_cache[key]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...