Search code examples
pythonserializationdill

How to dill a class and modify it later?


I am currently using the dill library for Python and I am using it to dill a class. This is the class

class QQQ:
    def __init__(self, name):
        self.name = name
        self.total = 0

    def add_1(self, add):
        self.total = 1 + add
        # To test the below after loading the saved dill
        # self.total = 101 + add

    @property
    def get_total(self):
        return self.total

Then I instantiate my class and dill it

import dill

path = '/path/file'
dill.settings['recurse'] = True
from x.qqq import QQQ

qqq = QQQ(name='Test1')
qqq.add_1(100)
with open(path, 'wb') as f:
    dill.dump(qqq, f)
class QQQ:
    def __init__(self, name):
        self.name = name
        self.total = 0

    def add_1(self, add):
        # self.total = 1 + add
        self.total = 101 + add

    @property
    def get_total(self):
        return self.total

Although, if I modify this QQQ class after dilling it then I load my dumped file:

import dill
path = '/path/file'
dill.settings['recurse'] = True

with open(path, 'rb') as f:
    old_class = dill.load(f)

old_class.add_1(100)
total = old_class.get_total

It uses the modified class and not the class I dilled earlier.


Solution

  • I'm the dill author. It ignores the stored class, because that was determined to be the proper thing to do. If you have redefined the class, then you have two choices, use the newly defined class... or ignore it and use the old class definition. Older versions of dill ignored the new class definition, but then that was deemed to not be the correct default behavior. Recent versions all will defer to any redefined class, by default.

    If you do want to ignore the new class definition, then you have to do it at load time, as noted below.

    >>> import dill
    >>> class QQQ(object):
    ...     def __init__(self):    
    ...         self.total = 0
    ...     def increment(self, n=1):
    ...         self.total += n
    ... 
    >>> q = QQQ() 
    >>> q.increment()
    >>> q.total
    1
    >>> dill.dump(q, open('qqq.pkl', 'wb'))
    >>> 
    

    And then restart your session. You get the new class definition, unless you use the ignore flag.

    >>> import dill
    >>> class QQQ(object):
    ...     def __init__(self):
    ...         self.total = 0
    ...     def increment(self, n=10):
    ...         self.total += n
    ...     def decrement(self, n=10):
    ...         self.total -= n
    ... 
    >>> q = dill.load(open('qqq.pkl', 'rb'))
    >>> q.total
    1
    >>> q.increment()
    >>> q.total
    11
    >>> p = dill.load(open('qqq.pkl', 'rb'), ignore=True)
    >>> p.total
    1
    >>> p.increment()
    >>> p.total
    2