为什么 Pickle 不像文档中所说的那样调用 __new__?

Why isn't Pickle calling __new__ like the documentation says?

documentation for Pickle具体说:

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,因此如果您使用默认协议,则必须更改它。