__getattr__, __setattr__ and pickle

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Tue Aug 12 11:52:59 EDT 2008


mwojc a écrit :
> Hi!
> My class with implemented __getattr__ and __setattr__ methods cannot be
> pickled because of the Error:
> 
> ======================================================================
> ERROR: testPickle (__main__.TestDeffnet2WithBiases)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>   File "deffnet.py", line 246, in testPickle
>     cPickle.dump(self.denet, file)
> TypeError: 'NoneType' object is not callable
> 
> ----------------------------------------------------------------------
> 
> Is there an obvious reason i don't know, which prevents pickling with those
> methods (if i comment them out the pickling test passes)?
> 
> I'm using Python 2.4.4 on Gentoo Linux. The mentioned methods goes as
> follows:
> 
>     def __setattr__(self, name, value):
>         if name == 'weights':
>             j = 0
>             for net in self.nets:
>                 w1 = self.wmarks[j]
>                 w2 = self.wmarks[j+1]
>                 net.weights = value[w1:w2]
>                 j += 1
>         else:
>             self.__dict__[name] = value
>     
>     def __getattr__(self, name):
>         if name == 'weights':
>             j = 0
>             for net in self.nets:
>                 w1 = self.wmarks[j]
>                 w2 = self.wmarks[j+1]
>                 self._weights[w1:w2] = net.weights
>                 j += 1
>             return self._weights

__getattr__ should raise an AttributeError when name != 'weight' instead 
of (implicitely) returning None. pickle looks for a couple special 
method in your object[1], and it looks like it doesn't bother to check 
if what it found was really callable.

[1] cf http://docs.python.org/lib/pickle-inst.html


FWIW, you'd be better using a property instead of __getattr__ / 
__setattr__ if possible. And while we're at it, you dont need to 
manually take care of your index in the for loop - you can use 
enumerate(iterable) instead:

              for j, net in enumerate(self.nets):
                  w1 = self.wmarks[j]
                  w2 = self.wmarks[j+1]
                  self._weights[w1:w2] = net.weights
              return self._weights


HTH




> Greetings,



More information about the Python-list mailing list