L
luvspython
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()
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()