eus*_*iro 1 python storage self globals python-3.x
在我的 python 脚本中,我有一个dict存储Processo对象的全局存储(一个简单的 global )。它在我的程序执行期间被填满。Processo由于性能原因,它的存在是为了避免创建重复的对象。
所以,对于class Processo我想在创建过程中验证它是否已经在全局存储上。
在这种情况下,我只想将其复制到self. 我正在使用getfromStorage()它。
class Processo:
def __init__(self, name, ...): # ... for simplicity
self.processoname = name
self = getfromStorage(self)
Run Code Online (Sandbox Code Playgroud)
不知道有没有用,但是...
def getfromStorage(processo):
if processo.processoname in process_storage:
return process_storage[processo.processoname]
return processo
Run Code Online (Sandbox Code Playgroud)
我如何做到这一点?我是否遗漏了什么或我的设计有问题?
这个模式不能用 合理地完成__init__,因为__init__只初始化一个已经存在的对象,你不能改变调用者将得到的东西(你可以重新绑定self,但这只会切断你正在创建的对象,调用者有他们的不受影响的单独别名)。
正确的方法是覆盖实际的构造函数,__new__,它允许您返回新实例,您可能会或可能不会创建:
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
Run Code Online (Sandbox Code Playgroud)
为了减少开销,我稍微重写了getfromStorage,所以它只需要名称并执行查找,如果失败则允许异常冒泡:
def getfromStorage(processoname):
return process_storage[processoname]
Run Code Online (Sandbox Code Playgroud)
这意味着,当可以使用缓存的实例时,不需要self重新构造不必要的对象。
注意:如果你这样做,通常最好不要定义__init__;对象的构造是通过调用类的__new__,然后隐式调用__init__结果来完成的。对于缓存的实例,您不希望它们重新初始化,因此您需要一个空的__init__(这样缓存的实例不会因为从缓存中检索而被修改)。将 all- __init__like 行为放在构造并返回新对象的代码中__new__,并且只对新对象执行它,以避免这个问题。