我有一个在首次使用后会被缓存的对象。我将使用cPickle模块执行此操作。如果模块已经被缓存,当我尝试下次(在另一个进程中)实例化对象时,我想使用缓存对象。以下是我的基本结构:
import cPickle
class Test(object):
def __new__(cls, name):
if name == 'john':
print "using cached object"
with open("cp.p", "rb") as f:
obj = cPickle.load(f)
print "object unpickled"
return obj
else:
print "using new object"
return super(Test, cls).__new__(cls, name)
def __init__(self, name):
print "calling __init__"
self.name = name
with open("cp.p", "wb") as f:
cPickle.dump(self, f)
问题在于,当我在__new__
方法中取消删除缓存对象时,它会调用__init__
并重新初始化所有内容。有趣的是,似乎在解开后不会调用__init__
,而是在返回未修改的对象时调用。我添加了一个显示此内容的打印语句("对象未标记")。
我通过在__init__
添加以下检查来解决问题:
intiailzed = False
...
...
def __init__(self, name):
if not self.intialized:
self.initialized = True
# Rest of the __init__ here
除了一个名为initialized的类属性外,这显然不太理想。
任何有关如何取消__init__
方法(或者为什么会被调用)的见解都将不胜感激。
编辑:根据反馈,这是我新提出的解决方案:
class Test(object):
def __new__(cls, name=None):
print "calling __new__"
if name == 'john':
print "using cached object"
with open("cp.p", "rb") as f:
obj = cPickle.load(f)
print "object unpickled"
return obj
else:
print "using new object"
obj = super(Test, cls).__new__(cls, name)
obj.initialize(name)
return obj
def __init__(self, name):
pass
def initialize(self, name):
print "calling __init__"
self.name = name
with open("cp.p", "wb") as f:
cPickle.dump(self, f)
答案 0 :(得分:3)
obj = Test(name)
的工作原理如下:
obj = Test.__new__(Test, name)
if isinstance(obj, Test):
obj.__init__(name)
由于从Test.__new__(Test, name)
返回的unpickled对象是Test
的实例,因此调用其__init__
方法。对象来自super(Test, cls).__new__
还是unpickling无关紧要。
为了避免这样的问题,覆盖__new__
的类通常应该从__new__
返回完全初始化的对象,而不是定义__init__
。他们的子类也应该遵循这个规则。