__getattr__, __setattr__ and pickle

mwojc mwojc at NOSPAMp.lodz.pl
Tue Aug 12 23:17:49 CEST 2008


Bruno Desthuilliers wrote:

> 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.

Yes, raising AttributeError helped. Thanks!

> 
> FWIW, you'd be better using a property instead of __getattr__ /
> __setattr__ if possible. 

You're probably right again, in this case it's better to use property.

> 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
> 
Sometimes i use manual handling of index because i'm convinced that
enumeration is a bit slower than this. But i'm not really sure about it...

Thanks again.

Greetings,
-- 
Marek



More information about the Python-list mailing list