<p>使用<code>__init__</code>无法合理地完成此模式,因为<code>__init__</code>只<em>初始化</em>一个已经存在的对象,并且您无法更改调用者将获得的内容(您可以重新绑定<code>self</code>,但这只会将您</em>与正在创建的对象断开,调用者有自己的独立别名,不受影响)</p>
<p>正确的方法是重写实际的构造函数<code>__new__</code>,它允许您<em>返回</em>新实例,您可以创建也可以不创建新实例:</p>
<pre><code>class Processo:
def __new__(cls, name, ...): # ... for simplicity
try:
# Try to return existing instance from storage
return getfromStorage(name)
except KeyError:
pass
# No instance existed, so create new object
self = super().__new__(cls) # Calls parent __new__ to make empty object
# Assign attributes as normal
self.processoname = name
# Optionally insert into storage here, e.g. with:
self = process_storage.setdefault(name, self)
# which will (at least for name of built-in type) atomically get either then newly
# constructed self, or an instance that was inserted by another thread
# between your original test and now
# If you're not on CPython, or name is a user-defined type where __hash__
# is implemented in Python and could allow the GIL to swap, then use a lock
# around this line, e.g. with process_storage_lock: to guarantee no races
# Return newly constructed object
return self
</code></pre>
<p>为了减少开销,我温和地重写了<code>getfromStorage</code>,因此它只取名称并执行查找,如果失败,允许异常冒泡:</p>
<pre><code>def getfromStorage(processoname):
return process_storage[processoname]
</code></pre>
<p>这意味着,当可以使用缓存实例时,不需要重新构造不必要的<code>self</code>对象</p>
<p>注意:如果这样做,通常最好不要定义<code>__init__</code>;对象的构造是通过调用类的<code>__new__</code>,然后对结果隐式调用<code>__init__</code>来完成的。对于缓存实例,您不希望重新初始化它们,因此需要一个空的<code>__init__</code>(这样缓存实例不会因为从缓存中检索而被修改)。将所有类似<code>__init__</code>的行为放在<code>__new__</code>中构造并返回新对象的代码中,并且只对新对象执行它,以避免此问题</p>