Here we check to see if we can use some of the code in the standard library pickle.py
to simplify our life and solve issue #5.
[2]:
from io import StringIO
import pickle
file = StringIO()
p = pickle.Pickler(file)
Old-style classes¶
[4]:
# No special methods: __dict__ is copied
class A:
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a))
print(a1.__dict__)
__init__(*(), **{})
{'y': 2}
[5]:
# __setstate__ passed __dict__
# __dict__ not updated explicitly
class A:
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
def __setstate__(self, state):
print('__setstate__({})'.format(state))
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a))
print(a1.__dict__)
__init__(*(), **{})
__setstate__({'y': 2})
{}
[6]:
# __getstate__ called instead of __dict__
class A:
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
def __getstate__(self):
print('__getstate__()')
return dict(x=1)
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a))
print(a1.__dict__)
__init__(*(), **{})
__getstate__()
{'x': 1}
[7]:
# __getstate__ called and passed to __setstate__
class A:
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
def __getstate__(self):
print('__getstate__()')
return dict(x=1)
def __setstate__(self, state):
print('__setstate__({})'.format(state))
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a))
print(a1.__dict__)
__init__(*(), **{})
__getstate__()
__setstate__({'x': 1})
{}
[8]:
# __getstate__ called and passed to __setstate__
# Both __init__ called (without kw) and __setstate__ called
# __dict__ ignored
class A:
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
def __getinitargs__(self):
print('__getinitargs__()')
return ('a', 3)
def __getstate__(self):
print('__getstate__()')
return dict(x=1)
def __setstate__(self, state):
print('__setstate__({})'.format(state))
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a))
print(a1.__dict__)
__init__(*(), **{})
__getstate__()
__setstate__({'x': 1})
{}
New-style classes¶
[9]:
# No special methods: __dict__ is copied
class A(object):
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a))
print(a1.__dict__)
__init__(*(), **{})
{'y': 2}
[10]:
# No special methods: __dict__ is copied
# __new__ is called for protocol >= 2
# __init__ is not called
class A(object):
def __new__(cls, *v, **kw):
print('__new__(*{}, **{})'.format(v, kw))
return object.__new__(cls)
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a, protocol=2))
print(a1.__dict__)
__new__(*(), **{})
__init__(*(), **{})
__new__(*(), **{})
{'y': 2}
[11]:
# __getinitargs__ ignored in new-style classes
# __dict__ is still copied
class A(object):
def __new__(cls, *v, **kw):
print('__new__(*{}, **{})'.format(v, kw))
return object.__new__(cls)
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
def __getinitargs__(self):
print('__getinitargs__()')
return ('a', 3)
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a, protocol=2))
print(a1.__dict__)
__new__(*(), **{})
__init__(*(), **{})
__new__(*(), **{})
{'y': 2}
[12]:
# __getnewargs__ called for protocol >= 2
# __dict__ still copied
class A(object):
def __new__(cls, *v, **kw):
print('__new__(*{}, **{})'.format(v, kw))
return object.__new__(cls)
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
def __getnewargs__(self):
print('__getnewargs__()')
return ('a', 3)
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a, protocol=2))
print(a1.__dict__)
__new__(*(), **{})
__init__(*(), **{})
__getnewargs__()
__new__(*('a', 3), **{})
{'y': 2}
[13]:
# __getnewargs__ called for protocol >= 2
# __dict__ still copied but from __getstate__ now
class A(object):
def __new__(cls, *v, **kw):
print('__new__(*{}, **{})'.format(v, kw))
return object.__new__(cls)
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
def __getnewargs__(self):
print('__getnewargs__()')
return ('a', 3)
def __getstate__(self):
print('__getstate__()')
return dict(x=1)
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a, protocol=2))
print(a1.__dict__)
__new__(*(), **{})
__init__(*(), **{})
__getnewargs__()
__getstate__()
__new__(*('a', 3), **{})
{'x': 1}
[14]:
# __getnewargs__ called for protocol >= 2
# __dict__ still copied but from __getstate__ now
class A(object):
def __new__(cls, *v, **kw):
print('__new__(*{}, **{})'.format(v, kw))
return object.__new__(cls)
def __init__(self, *v, **kw):
print('__init__(*{}, **{})'.format(v, kw))
def __getnewargs__(self):
print('__getnewargs__()')
return ('a', 3)
def __getstate__(self):
print('__getstate__()')
return dict(x=1)
def __setstate__(self, state):
print('__setstate__({})'.format(state))
a = A()
a.y = 2
a1 = pickle.loads(pickle.dumps(a, protocol=2))
print(a1.__dict__)
__new__(*(), **{})
__init__(*(), **{})
__getnewargs__()
__getstate__()
__new__(*('a', 3), **{})
__setstate__({'x': 1})
{}
Summary¶
- With new-style classes,
__init__
is never called. One must define everything by updating__dict__
or calling__setstate__
.
[16]:
import sys
sys.path.insert(0, '../..')
import persist.archive
import persist.interfaces
a = persist.archive.Archive(scoped=False)
a.insert(f=persist.archive._from_pickle_state)
print(str(a))
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-16-fc296a285c9d> in <module>
5
6 a = persist.archive.Archive(scoped=False)
----> 7 a.insert(f=persist.archive._from_pickle_state)
8 print(str(a))
AttributeError: module 'persist.archive' has no attribute '_from_pickle_state'
[21]:
import numpy as np
import uncertainties
np.random.seed(3)
cov = np.random.random((3, 3))
x = [1, 2, 3]
u = uncertainties.correlated_values(
nom_values=x, covariance_mat=cov, tags=['a', 'b', 'c'])
u = uncertainties.ufloat(0.1, 0.2)
[22]:
import persist.archive
a = persist.archive.Archive()
a.insert(u=u)
print(str(a))
Traceback (most recent call last):
File "/data/apps/conda/envs/work/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3441, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-22-df2ce861ec8f>", line 4, in <module>
print(str(a))
File "/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py", line 1265, in __str__
res = self.scoped__str__()
File "/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py", line 1302, in scoped__str__
graph = _Graph(objects=self.arch,
File "/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py", line 2311, in __init__
node = self._new_node(obj, env, name)
File "/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py", line 2333, in _new_node
rep, args, imports = self.get_persistent_rep(obj, env)
File "/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py", line 789, in get_persistent_rep
return get_persistent_rep_repr(obj, env, rep=rep)
File "/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py", line 1644, in get_persistent_rep_repr
_ast = AST(rep)
File "/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py", line 2681, in __init__
self.__dict__['ast'] = ast.parse(expr)
File "/data/apps/conda/envs/work/lib/python3.8/ast.py", line 47, in parse
return compile(source, filename, mode, flags,
File "<unknown>", line 1
0.1+/-0.2
^
SyntaxError: invalid syntax