为什么 Pickle 不像文档中所说的那样调用 __new__?
Why isn't Pickle calling __new__ like the documentation says?
Instances of a new-style class C are created using:
obj = C.__new__(C, *args)
试图利用这一点,我创建了一个没有实例属性或方法的单例:
class ZeroResultSentinel(object):
instance = None
def __new__(cls, *args):
if not cls.instance:
cls.instance = super(ZeroResultSentinel, cls).__new__(cls, *args)
return cls.instance
(此class用于缓存层,以区分缓存中无结果和无结果。)
单例运行良好(每次调用 ZeroResultSentinel()
都会在内存中产生相同的实例,并且 ZeroResultSentinel() == ZeroResultSentinel()
的计算结果为 True
)。我 可以 无错误地 pickle 和 unpickle 实例。但是,当我解开它时,我得到了一个不同的实例。所以我在 __new__
内放置了一个断点。我每次调用 ZeroResultSentinel()
都会遇到断点,但是当我解开 pickled ZeroResultSentinel
时我不会遇到断点。这与文档直接矛盾。那么是我做错了什么,还是文档不正确?
文档并没有真正说清楚,但是您的 __new__
方法将仅用于 pickle 协议 2 及更高版本:
>>> class Foo(object):
... def __new__(cls):
... print "New"
... return object.__new__(cls)
...
>>> foo = Foo()
New
>>> pickle.loads(pickle.dumps(foo, protocol=0))
<__main__.Foo object at 0x00000000025E9A20>
>>> pickle.loads(pickle.dumps(foo, protocol=2))
New
<__main__.Foo object at 0x00000000022A3F60>
在 Python 2 上,默认协议为 0,因此如果您使用默认协议,则必须更改它。
Instances of a new-style class C are created using:
obj = C.__new__(C, *args)
试图利用这一点,我创建了一个没有实例属性或方法的单例:
class ZeroResultSentinel(object):
instance = None
def __new__(cls, *args):
if not cls.instance:
cls.instance = super(ZeroResultSentinel, cls).__new__(cls, *args)
return cls.instance
(此class用于缓存层,以区分缓存中无结果和无结果。)
单例运行良好(每次调用 ZeroResultSentinel()
都会在内存中产生相同的实例,并且 ZeroResultSentinel() == ZeroResultSentinel()
的计算结果为 True
)。我 可以 无错误地 pickle 和 unpickle 实例。但是,当我解开它时,我得到了一个不同的实例。所以我在 __new__
内放置了一个断点。我每次调用 ZeroResultSentinel()
都会遇到断点,但是当我解开 pickled ZeroResultSentinel
时我不会遇到断点。这与文档直接矛盾。那么是我做错了什么,还是文档不正确?
文档并没有真正说清楚,但是您的 __new__
方法将仅用于 pickle 协议 2 及更高版本:
>>> class Foo(object):
... def __new__(cls):
... print "New"
... return object.__new__(cls)
...
>>> foo = Foo()
New
>>> pickle.loads(pickle.dumps(foo, protocol=0))
<__main__.Foo object at 0x00000000025E9A20>
>>> pickle.loads(pickle.dumps(foo, protocol=2))
New
<__main__.Foo object at 0x00000000022A3F60>
在 Python 2 上,默认协议为 0,因此如果您使用默认协议,则必须更改它。