在 class X 的 __new__ 方法中对类型 X 的 Unpickling 对象在返回 unpickled 对象时调用 __init__,为什么?
Unpickling object of type X in the __new__ method of class X calls __init__ on returning the unpickled object, why?
我有一个对象,它会在第一次使用后被缓存。我将使用 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__
似乎不是在 unpickling 之后调用的,而是在返回 unpickled 对象时调用的。我添加了一个显示此内容的打印语句 ("object unpickled")。
我有一个 hacky 解决方法,将以下检查添加到 __init__
:
intiailzed = False
...
...
def __init__(self, name):
if not self.intialized:
self.initialized = True
# Rest of the __init__ here
还有一个class属性叫做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)
obj = Test(name)
是这样工作的:
obj = Test.__new__(Test, name)
if isinstance(obj, Test):
obj.__init__(name)
由于从 Test.__new__(Test, name)
编辑的未腌制对象 return 是 Test
的一个实例,它的 __init__
方法被调用。对象来自 super(Test, cls).__new__
还是 unpickling 并不重要。
为避免此类问题,覆盖 __new__
的 类 通常应 return 来自 __new__
的完全初始化对象,而不是定义 __init__
。他们的子类也应该遵循这个规则
我有一个对象,它会在第一次使用后被缓存。我将使用 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__
似乎不是在 unpickling 之后调用的,而是在返回 unpickled 对象时调用的。我添加了一个显示此内容的打印语句 ("object unpickled")。
我有一个 hacky 解决方法,将以下检查添加到 __init__
:
intiailzed = False
...
...
def __init__(self, name):
if not self.intialized:
self.initialized = True
# Rest of the __init__ here
还有一个class属性叫做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)
obj = Test(name)
是这样工作的:
obj = Test.__new__(Test, name)
if isinstance(obj, Test):
obj.__init__(name)
由于从 Test.__new__(Test, name)
编辑的未腌制对象 return 是 Test
的一个实例,它的 __init__
方法被调用。对象来自 super(Test, cls).__new__
还是 unpickling 并不重要。
为避免此类问题,覆盖 __new__
的 类 通常应 return 来自 __new__
的完全初始化对象,而不是定义 __init__
。他们的子类也应该遵循这个规则