Unpickle error -- "object has no attribute ...."

luvspython srehtvandy at gmail.com
Sun Aug 28 20:00:03 EDT 2011


I have an application that needs to keep a history of the values of
several attributes of each of many instances of many classes.  The
history-keeping logic is in a helper class, HistoryKeeper, that's
inherited by classes like Vehicle in the example below.

Pickling an instance of Vehicle works, but unpickling fails with:
 "Vehicle object has no attribute
'_orderedArgNames'"   (_orderedArgNames is an attribute in
HistoryKeeper that tells the attributes for which history must be
kept.)

During unpickling, the exception occurs at the 2nd line in the
__getattribute__ method:
        if item not in object.__getattribute__(self,
'_orderedArgNames'):

FWIW, cPickle fails the same way.

Below is a stripped-down example that fails in unpickling.

Can anyone explain why it fails and what I can do to fix it?

MANY thanks.

=========================================================

import datetime, bisect
from collections import OrderedDict



# define a class which helps keep date-history of attribute settings
in inheriting classes
class HistoryKeeper(object):
    """ Class to maintain a dated history of attribute settings in
inheriting classes.
    The initialization arguments are in an OrderedDict."""
    def __init__(self, orderedArgs):
        super(HistoryKeeper, self).__setattr__('_orderedArgNames',
orderedArgs.keys())   #remember the order of unnamed args
        for arg, value in orderedArgs.items():
            if arg != 'self':
                self.Set(arg, value)


    """ Get the current value of an attribute, optionally returning
its entire history."""
    def __getattribute__(self, item, returnHistory=False):
        value = object.__getattribute__(self, item)
        if item not in object.__getattribute__(self,
'_orderedArgNames'):
            return value         # not an attribute for which we
maintain a change history
        elif returnHistory:
            return value         # return the entire history
        else:
            return value[-1][0]  # return only the latest
value


    """ Set an attribute by appending the new value and date to
existing history of that attribute.
    Unless a setting-date is supplied, default to today.
    Set the value only if it's different than the chronological
immediately preceding value."""
    def __setattr__(self, item, value, date=None):

        # avoid history keeping if this item isn't among those
declared to require it
        if item not in self._orderedArgNames:
            super(HistoryKeeper, self).__setattr__(item, value)
        else:
            if not date:
                date = datetime.date.today()
            # if this attribute has already been set, add this value
to that history
            try:
                history = self.__getattribute__(item,
returnHistory=True)
                # if a date was supplied, ensure the history remains
in chronological order
                dates = [val[1] for val in history]
                index = bisect.bisect_right(dates, date)
                # insert this value into the history unless it doesn't
change an existing setting
                if index == 0 or history[index-1][0] != value:
                    history.insert(index, (value,date))
            except:
                history = [(value, date)]
            super(HistoryKeeper, self).__setattr__(item, history)

    def Set(self, item, value):
        self.__setattr__(item, value)




class Vehicle(HistoryKeeper):
    def __init__(self, tag, make, model):
        argDict = OrderedDict([('tag',tag),('make',make),
('model',model)])
        super(Vehicle, self).__init__(argDict)

if __name__ == "__main__":
    car = Vehicle('TAG123', 'FORD', 'Model A')

    import pickle
    pFile = open('car.pk1', 'wb')
    pickle.dump(car, pFile, -1)
    pFile.close()
    print "car pickled OK"

    pFile = open('car.pk1', 'rb')
    community = pickle.load(pFile)
    pFile.close()



More information about the Python-list mailing list