Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

The documentation for Pickle specifically says:

Instances of a new-style class C are created using:

obj = C.__new__(C, *args)

Attempting to take advantage of this, I created a singleton with no instance attributes or methods:

class ZeroResultSentinel(object):
    instance = None
    def __new__(cls, *args):
        if not cls.instance:
            cls.instance = super(ZeroResultSentinel, cls).__new__(cls, *args)
        return cls.instance

(This class is used in a caching layer to differentiate a no-result result from nothing in the cache.)

The singleton works great (every call to ZeroResultSentinel() results in the same instance in memory, and ZeroResultSentinel() == ZeroResultSentinel() evaluates to True). And I can pickle and unpickle the instance without errors. However, when I unpickle it, I get a different instance. So I placed a breakpoint within __new__. I hit the breakpoint every time I call ZeroResultSentinel(), but I do not hit a breakpoint when I unpickle a pickled ZeroResultSentinel. This is in direct contradiction to the documentation. So am I doing something wrong, or is the documentation incorrect?

like image 490
Nick Williams Avatar asked Apr 17 '16 02:04

Nick Williams


People also ask

Why pickle is not good in Python?

Pickle is unsafe because it constructs arbitrary Python objects by invoking arbitrary functions. However, this is also gives it the power to serialize almost any Python object, without any boilerplate or even white-/black-listing (in the common case).

How do you call a pickle file?

To use pickle, start by importing it in Python. To pickle this dictionary, you first need to specify the name of the file you will write it to, which is dogs in this case. Note that the file does not have an extension. To open the file for writing, simply use the open() function.

What Cannot be pickled in Python?

With pickle protocol v1, you cannot pickle open file objects, network connections, or database connections.


1 Answers

The documentation doesn't really make it clear, but your __new__ method will only be used for pickle protocol 2 and up:

>>> 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>

On Python 2, the default protocol is 0, so if you're using the default, you'll have to change that.

like image 183
user2357112 supports Monica Avatar answered Sep 27 '22 17:09

user2357112 supports Monica