正如 theheadofabroom 和我在评论中已经提到的那样,在依赖非哈希值(例如缓存或记忆)时存在一些可能性。因此,如果您仍然想这样做,以下示例不会隐藏__new__
or__init__
方法中的记忆。(自我记忆类会很危险,因为记忆标准可能会被您无法控制的代码所欺骗)。
相反,我提供了一个函数memoize
,它返回一个类的记忆工厂函数。由于没有通用的方法来区分不可散列的参数,如果它们会产生一个与已经存在的实例等效的实例,则必须显式地提供记忆语义。这是通过将keyfunc
函数传递给memoize
. keyfunc
采用与类的方法相同的参数__init__
并返回一个可散列键,其相等关系 ( __eq__
) 确定记忆。
memoization 的正确使用是 using 代码的责任(提供一个keyfunc
sensible 和 using 工厂),因为要 memoized 的类没有被修改,仍然可以正常实例化。
def memoize(cls, keyfunc):
memoized_instances = {}
def factory(*args, **kwargs):
key = keyfunc(*args, **kwargs)
if key in memoized_instances:
return memoized_instances[key]
instance = cls(*args, **kwargs)
memoized_instances[key] = instance
return instance
return factory
class MemoTest1(object):
def __init__(self, value):
self.value = value
factory1 = memoize(MemoTest1, lambda value : value)
class MemoTest2(MemoTest1):
def __init__(self, value, foo):
MemoTest1.__init__(self, value)
self.foo = foo
factory2 = memoize(MemoTest2, lambda value, foo : (value, frozenset(foo)))
m11 = factory1('test')
m12 = factory1('test')
assert m11 is m12
m21 = factory2('test', [1, 2])
lst = [1, 2]
m22 = factory2('test', lst)
lst.append(3)
m23 = factory2('test', lst)
assert m21 is m22
assert m21 is not m23
我只是将MemoTest2
其作为子类包含在内,MemoTest1
以表明使用常规类继承没有任何魔力。