在Python中,如何重用现有的相等的不可变对象(如str
所做的那样)?这可以通过定义__hash__
方法来完成,还是需要更复杂的措施呢?
答案 0 :(得分:13)
如果你想通过类构造函数创建并让它返回一个先前创建的对象,那么你需要提供一个__new__
方法(因为当你到达__init__
时,该对象已经已创建)。
这是一个简单的例子 - 如果之前已经看到用于初始化的值,则返回先前创建的对象而不是创建的新对象:
class Cached(object):
"""Simple example of immutable object reuse."""
def __init__(self, i):
self.i = i
def __new__(cls, i, _cache={}):
try:
return _cache[i]
except KeyError:
# you must call __new__ on the base class
x = super(Cached, cls).__new__(cls)
x.__init__(i)
_cache[i] = x
return x
请注意,对于此示例,只要可以清除,您就可以使用任何内容进行初始化。并且只是为了表明对象真正被重用:
>>> a = Cached(100)
>>> b = Cached(200)
>>> c = Cached(100)
>>> a is b
False
>>> a is c
True
答案 1 :(得分:3)
我相信您必须保留已创建的实例的dict {args:object},然后覆盖类'__new__
方法以检入该字典,并返回相关对象(如果已存在)。请注意,我没有实现或测试这个想法。当然,字符串是在C级处理的。
答案 2 :(得分:3)
有两个'软件工程'解决方案,不需要任何低级Python知识。它们适用于以下场景:
第一个场景:如果使用相同的构造函数参数构造类,则它们的对象是“相等的”,并且构造后相等性不会随时间而变化。 解决方案:使用散列构造函数参数的工厂:
class MyClass:
def __init__(self, someint, someotherint):
self.a = someint
self.b = someotherint
cachedict = { }
def construct_myobject(someint, someotherint):
if (someint, someotherint) not in cachedict:
cachedict[(someint, someotherint)] = MyClass(someint, someotherint)
return cachedict[(someint, someotherint)]
这种方法实质上将您的类的实例限制为每个不同输入对的一个唯一对象。还有明显的缺点:并非所有类型都易于清洗等等。
第二种情景:您班级的对象是可变的,他们的“平等”可能会随着时间而改变。 解决方案:定义相等实例的类级别注册表:
class MyClass:
registry = { }
def __init__(self, someint, someotherint, third):
MyClass.registry[id(self)] = (someint, someotherint)
self.someint = someint
self.someotherint = someotherint
self.third = third
def __eq__(self, other):
return MyClass.registry[id(self)] == MyClass.registry[id(other)]
def update(self, someint, someotherint):
MyClass.registry[id(self)] = (someint, someotherint)
在此示例中,具有相同someint, someotherint
对的对象相等,而第三个参数不考虑因素。诀窍是使registry
中的参数保持同步。作为update
的替代方案,您可以为您的班级覆盖getattr
和setattr
;这将确保任何作业foo.someint = y
与您的班级词典保持同步。查看示例here。