5

I found a lot of threads about this but the problem of all of them is the namespace. My problem have nothing to do with namespace.

A small example:

import cPickle as pickle
from uncertainties import Variable

class value(Variable):
    def __init__(self, args, showing=False):
        self.show = showing
        Variable.__init__(self, args[0], args[1])

val = value((3,1), True)
print val.nominal_value, val.std_dev(), val.show
fobj = file("pickle.file", "w")
pickle.dump(val, fobj)
fobj.close()

fobj = file("pickle.file", "r")
val = pickle.load(fobj)
fobj.close()
print val.nominal_value, val.std_dev(), val.show

The output of this code:

3.0 1.0 True
3.0 1.0
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/usr/lib/python2.7/dist-packages/IPython/utils/py3compat.pyc in execfile(fname, *where)
    173             else:
    174                 filename = fname
--> 175             __builtin__.execfile(filename, *where)

/home/markus/pickle.py in <module>()
     19 val = pickle.load(fobj)
     20 fobj.close()
---> 21 print val.nominal_value, val.std_dev(), val.show

AttributeError: 'value' object has no attribute 'show'

The namespace is the same at pickling and unpickling. All attributes of uncertainties.Variable are restored - only my added one "show" is missed.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Chickenmarkus
  • 1,131
  • 11
  • 25
  • 1
    What is the `uncertainties` module? Where does it come from? – Martijn Pieters Feb 27 '13 at 16:39
  • Are you able to come up with a self-contained example of this, i.e. one that we can experiment with? – NPE Feb 27 '13 at 16:44
  • @NPE: I was able to reproduce it once I located the [`uncertainties` project](http://pythonhosted.org/uncertainties/); it uses a custom `__getstate__` method. – Martijn Pieters Feb 27 '13 at 17:00
  • I was not allowed to post links as new user. But I found this module on original python.org page: https://pypi.python.org/pypi/uncertainties/ – Chickenmarkus Feb 27 '13 at 18:51

1 Answers1

6

The uncertainties.Variable() class uses a __slots__ attribute to save memory. As a result, to be pickleable, it must define a __getstate__ method as well (see Why am I getting an error about my class defining __slots__ when trying to pickle an object?).

If you need to add your own additional attributes, you'll have to override that __getstate__ method. Declaring your additional attributes in a __slot__ attribute of your own is probably a good idea too:

from uncertainties import Variable

class value(Variable):
    __slots__ = ('show',)  # only list *additional* slots

    def __init__(self, args, showing=False):
        self.show = showing
        super(value, self).__init__(args[0], args[1])

    def __getstate__(self):
        obj_slot_values = {}
        for cls in type(self).mro():
            obj_slot_values.update((k, getattr(self, k)) for k in getattr(cls, '__slots__', ()))
        # Conversion to a usual dictionary:
        return obj_slot_values

This new __getstate__ is required because the Variable.__getstate__ method assumes that there will only be one __slots__ attribute, while each class in the MRO may have one instead.

This is really a limitation of the uncertainties library; I've submitted a pull request that addresses this and would remove the need to override the __getstate__ method in a subclass.

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • OK, "simple" way but hard to find with this general AttributeError. Thank a lot. – Chickenmarkus Feb 27 '13 at 18:53
  • @Chickenmarkus: Thanks to Martijn, who sent me a patch, the latest Github version of uncertainties makes your `value` class directly pickeable without having to define your own `__getstate__()`. – Eric O. Lebigot Feb 28 '13 at 14:30
  • 1
    @Chickenmarkus: I just uploaded version 1.9.1 of my uncertainties package (https://pypi.python.org/pypi/uncertainties/): your subclass should now be directly pickleable (no need to define your own `__getstate__`. – Eric O. Lebigot Mar 01 '13 at 07:42
  • 1
    @EOL: Yes, with version 1.9.1 my first example works now too. Thanks. – Chickenmarkus Mar 04 '13 at 14:36