如何从静态方法中创建类的实例?

5

这是我的问题。我创建了一个相当复杂的只读类,它使用静态的“工厂”方法进行许多数据库调用。该方法的目标是通过查找已创建对象池中的相同实例(相同类型,相同初始化参数)来避免破坏数据库。

如果找到了某些内容,该方法将只返回它。没有问题。但是如果没有找到,我该如何创建对象的实例,并使其与继承方式一起工作?

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

谢谢。

1
为什么这么复杂?为什么不直接使用getInstance(A,'foo')或者getInstance(b,'bar')呢? - S.Lott
实际的类比示例中的类稍微复杂一些。其实这部分是缺失的,没错 :) - Pierre
3个回答

5
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(identifier)来获取相同的对象。如果我理解正确,就是cls(identifier)会访问数据库,这就是您想要尽可能少调用的内容(因为您知道这些对象是不可变的)。
如果您希望即使这些对象在其他地方不再被引用也将它们保留在缓存中,则将WeakValueDictionary更改为普通字典。
这需要identifier适合作为字典键,如果它是一个字符串(如您在示例代码中所示),那么它就是适合的。

非常感谢。正是我在寻找的东西。你理解得很正确 :) - Pierre

1

一种常见的方法是这样的。

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 )

我们将池与被池化的对象分开。它们彼此无关。

您可以随意对被池化的对象进行子类化。

您可以独立地更改池策略,而不会破坏或重新测试被池化的对象。


是的,谢谢。实际上,我想做的不是一个常规的池子。我不想有很多类做同样的事情并按需取用其中一个。我只有一个实例对应一个特定的初始化参数(比如用户 ID),我希望每次都能返回正确的实例,而不将其从池子中移除(该类支持并发访问,因为它是只读的…)。 - Pierre
我想每次返回正确的实例,而不从池中删除它。你的意思是你想要一个对象字典吗? - S.Lott

0
深入探讨S.Lott的评论:

“我想每次返回正确的实例,而不从池中移除它。” 你的意思是你想要一个对象的字典吗?-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]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接