{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "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](https://bitbucket.org/mforbes/persist/issue/5/use-pickle-protocol-if-provided)." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from io import StringIO\n", "import pickle\n", "file = StringIO()\n", "p = pickle.Pickler(file)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Old-style classes " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__init__(*(), **{})\n", "{'y': 2}\n" ] } ], "source": [ "# No special methods: __dict__ is copied\n", "class A:\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", "\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__init__(*(), **{})\n", "__setstate__({'y': 2})\n", "{}\n" ] } ], "source": [ "# __setstate__ passed __dict__\n", "# __dict__ not updated explicitly\n", "class A:\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", " def __setstate__(self, state):\n", " print('__setstate__({})'.format(state))\n", "\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__init__(*(), **{})\n", "__getstate__()\n", "{'x': 1}\n" ] } ], "source": [ "# __getstate__ called instead of __dict__\n", "class A:\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", " def __getstate__(self):\n", " print('__getstate__()')\n", " return dict(x=1)\n", "\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__init__(*(), **{})\n", "__getstate__()\n", "__setstate__({'x': 1})\n", "{}\n" ] } ], "source": [ "# __getstate__ called and passed to __setstate__\n", "class A:\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", " def __getstate__(self):\n", " print('__getstate__()')\n", " return dict(x=1)\n", " def __setstate__(self, state):\n", " print('__setstate__({})'.format(state))\n", "\n", "\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__init__(*(), **{})\n", "__getstate__()\n", "__setstate__({'x': 1})\n", "{}\n" ] } ], "source": [ "# __getstate__ called and passed to __setstate__\n", "# Both __init__ called (without kw) and __setstate__ called\n", "# __dict__ ignored\n", "class A:\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", " def __getinitargs__(self):\n", " print('__getinitargs__()')\n", " return ('a', 3)\n", " def __getstate__(self):\n", " print('__getstate__()')\n", " return dict(x=1)\n", " def __setstate__(self, state):\n", " print('__setstate__({})'.format(state))\n", "\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a))\n", "print(a1.__dict__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# New-style classes" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__init__(*(), **{})\n", "{'y': 2}\n" ] } ], "source": [ "# No special methods: __dict__ is copied\n", "class A(object):\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", "\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__new__(*(), **{})\n", "__init__(*(), **{})\n", "__new__(*(), **{})\n", "{'y': 2}\n" ] } ], "source": [ "# No special methods: __dict__ is copied\n", "# __new__ is called for protocol >= 2\n", "# __init__ is not called\n", "class A(object):\n", " def __new__(cls, *v, **kw):\n", " print('__new__(*{}, **{})'.format(v, kw))\n", " return object.__new__(cls)\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", "\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a, protocol=2))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__new__(*(), **{})\n", "__init__(*(), **{})\n", "__new__(*(), **{})\n", "{'y': 2}\n" ] } ], "source": [ "# __getinitargs__ ignored in new-style classes\n", "# __dict__ is still copied\n", "class A(object):\n", " def __new__(cls, *v, **kw):\n", " print('__new__(*{}, **{})'.format(v, kw))\n", " return object.__new__(cls)\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", " def __getinitargs__(self):\n", " print('__getinitargs__()')\n", " return ('a', 3)\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a, protocol=2))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__new__(*(), **{})\n", "__init__(*(), **{})\n", "__getnewargs__()\n", "__new__(*('a', 3), **{})\n", "{'y': 2}\n" ] } ], "source": [ "# __getnewargs__ called for protocol >= 2\n", "# __dict__ still copied\n", "class A(object):\n", " def __new__(cls, *v, **kw):\n", " print('__new__(*{}, **{})'.format(v, kw))\n", " return object.__new__(cls)\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", " def __getnewargs__(self):\n", " print('__getnewargs__()')\n", " return ('a', 3)\n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a, protocol=2))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__new__(*(), **{})\n", "__init__(*(), **{})\n", "__getnewargs__()\n", "__getstate__()\n", "__new__(*('a', 3), **{})\n", "{'x': 1}\n" ] } ], "source": [ "# __getnewargs__ called for protocol >= 2\n", "# __dict__ still copied but from __getstate__ now\n", "class A(object):\n", " def __new__(cls, *v, **kw):\n", " print('__new__(*{}, **{})'.format(v, kw))\n", " return object.__new__(cls)\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", " def __getnewargs__(self):\n", " print('__getnewargs__()')\n", " return ('a', 3)\n", " def __getstate__(self):\n", " print('__getstate__()')\n", " return dict(x=1)\n", " \n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a, protocol=2))\n", "print(a1.__dict__)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__new__(*(), **{})\n", "__init__(*(), **{})\n", "__getnewargs__()\n", "__getstate__()\n", "__new__(*('a', 3), **{})\n", "__setstate__({'x': 1})\n", "{}\n" ] } ], "source": [ "# __getnewargs__ called for protocol >= 2\n", "# __dict__ still copied but from __getstate__ now\n", "class A(object):\n", " def __new__(cls, *v, **kw):\n", " print('__new__(*{}, **{})'.format(v, kw))\n", " return object.__new__(cls)\n", " def __init__(self, *v, **kw):\n", " print('__init__(*{}, **{})'.format(v, kw))\n", " def __getnewargs__(self):\n", " print('__getnewargs__()')\n", " return ('a', 3)\n", " def __getstate__(self):\n", " print('__getstate__()')\n", " return dict(x=1)\n", " def __setstate__(self, state):\n", " print('__setstate__({})'.format(state)) \n", " \n", "a = A()\n", "a.y = 2\n", "a1 = pickle.loads(pickle.dumps(a, protocol=2))\n", "print(a1.__dict__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* With new-style classes, ``__init__`` is never called. One must define everything by updating ``__dict__`` or calling ``__setstate__``.\n" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "module 'persist.archive' has no attribute '_from_pickle_state'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpersist\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marchive\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mArchive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mscoped\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minsert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mpersist\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marchive\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_from_pickle_state\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mAttributeError\u001b[0m: module 'persist.archive' has no attribute '_from_pickle_state'" ] } ], "source": [ "import sys\n", "sys.path.insert(0, '../..')\n", "import persist.archive\n", "import persist.interfaces\n", "\n", "a = persist.archive.Archive(scoped=False)\n", "a.insert(f=persist.archive._from_pickle_state)\n", "print(str(a))" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import uncertainties\n", "np.random.seed(3)\n", "cov = np.random.random((3, 3))\n", "x = [1, 2, 3]\n", "u = uncertainties.correlated_values(\n", " nom_values=x, covariance_mat=cov, tags=['a', 'b', 'c'])\n", "u = uncertainties.ufloat(0.1, 0.2)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "ename": "SyntaxError", "evalue": "invalid syntax (, line 1)", "output_type": "error", "traceback": [ "Traceback \u001b[0;36m(most recent call last)\u001b[0m:\n", " File \u001b[1;32m\"/data/apps/conda/envs/work/lib/python3.8/site-packages/IPython/core/interactiveshell.py\"\u001b[0m, line \u001b[1;32m3441\u001b[0m, in \u001b[1;35mrun_code\u001b[0m\n exec(code_obj, self.user_global_ns, self.user_ns)\n", " File \u001b[1;32m\"\"\u001b[0m, line \u001b[1;32m4\u001b[0m, in \u001b[1;35m\u001b[0m\n print(str(a))\n", " File \u001b[1;32m\"/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py\"\u001b[0m, line \u001b[1;32m1265\u001b[0m, in \u001b[1;35m__str__\u001b[0m\n res = self.scoped__str__()\n", " File \u001b[1;32m\"/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py\"\u001b[0m, line \u001b[1;32m1302\u001b[0m, in \u001b[1;35mscoped__str__\u001b[0m\n graph = _Graph(objects=self.arch,\n", " File \u001b[1;32m\"/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py\"\u001b[0m, line \u001b[1;32m2311\u001b[0m, in \u001b[1;35m__init__\u001b[0m\n node = self._new_node(obj, env, name)\n", " File \u001b[1;32m\"/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py\"\u001b[0m, line \u001b[1;32m2333\u001b[0m, in \u001b[1;35m_new_node\u001b[0m\n rep, args, imports = self.get_persistent_rep(obj, env)\n", " File \u001b[1;32m\"/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py\"\u001b[0m, line \u001b[1;32m789\u001b[0m, in \u001b[1;35mget_persistent_rep\u001b[0m\n return get_persistent_rep_repr(obj, env, rep=rep)\n", " File \u001b[1;32m\"/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py\"\u001b[0m, line \u001b[1;32m1644\u001b[0m, in \u001b[1;35mget_persistent_rep_repr\u001b[0m\n _ast = AST(rep)\n", " File \u001b[1;32m\"/data/apps/conda/envs/work/lib/python3.8/site-packages/persist/archive.py\"\u001b[0m, line \u001b[1;32m2681\u001b[0m, in \u001b[1;35m__init__\u001b[0m\n self.__dict__['ast'] = ast.parse(expr)\n", "\u001b[0;36m File \u001b[0;32m\"/data/apps/conda/envs/work/lib/python3.8/ast.py\"\u001b[0;36m, line \u001b[0;32m47\u001b[0;36m, in \u001b[0;35mparse\u001b[0;36m\u001b[0m\n\u001b[0;31m return compile(source, filename, mode, flags,\u001b[0m\n", "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 0.1+/-0.2\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" ] } ], "source": [ "import persist.archive\n", "a = persist.archive.Archive()\n", "a.insert(u=u)\n", "print(str(a))" ] } ], "metadata": { "kernelspec": { "display_name": "Python [conda env:work]", "language": "python", "name": "conda-env-work-py" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 1 }