half object/half dictionary
Manuel M. Garcia
mgarcia at cole-switches.com
Mon Dec 9 14:24:47 EST 2002
I wrote a metaclass(?) for manipulating a class with __slots__ as a
dictionary. It is to avoid sections of code like this:
abc.customer = xyz.customer
abc.work_order = xyz.work_order
abc.purchase_order = xyz.purchase_order
(20 more lines)
Instead I would do this:
abc.update(xyz)
Also I can grab all the attribute names, and create a table on the fly
with those attribute names as column names.
I like "abc.customer" better than "abc['customer']" for the obvious
reason, and also because it lets me use PythonWin's
auto-attribute-completion when I type the period.
I might use it like this:
class stockroom_part_class(HalfObjectHalfDict):
__slots__ = ( 'stock_class_code', 'part_number', 'inventory_type',
'mfg_or_purch', 'part_accounting_value',
'part_current_revision', 'part_description',
'part_status', 'product_family', 'product_model',
'qty_onhand', 'qty_used_last_year',
'qty_used_this_year', 'allocated_manufacturing',
'first_component_part', 'made_on_assembly',
'first_routing_sequence', 'last_routing_sequence',
'has_routing', 'stocking_unit_of_measure',
'bin_item', 'safety_stock')
As you can guess, I want to automate the code for all these attributes
as much as possible.
The code for this "metaclass" is at the end of this post.
Anyway, is this really a "metaclass"? I guess I should be using
"__metaclass__", but I really don't understand the difference between
setting "__metaclass__" and regular subclassing. I don't understand
the difference between "__init__" and "__new__".
Does it make sense for a class to have more than one "__metaclass__"
set?
Metaclasses typically subclass 'type', right?
I haven't found any documentation on Python metaclasses that I
understand. What is everyone's favorite reference on Python
metaclasses?
Manuel
(code follows)
class HalfObjectHalfDict(object):
"""Subclass to make object you can operate on like a dictionary.
Assumes you are setting __slots__
"""
#
__slots__ = ()
#
def __init__(self, *args0, **args1):
self.Update(*args0, **args1)
#
def __len__(self):
return len(self.SlotsDict())
#
def __contains__(self, item):
return item in self.SlotsDict()
#
def __iter__(self):
return iter(self.SlotsDict())
#
def __getitem__(self, key):
if self.IsInSlots(key):
try:
value = self.__getattribute__(key)
except AttributeError:
raise KeyError(key)
else:
return value
else:
raise KeyError(key)
#
def __setitem__(self, key, value):
if not self.IsInSlots(key):
raise AttributeError
self.__setattr__(key, value)
#
def Slots(self):
return self.__class__.__slots__
#
def IsInSlots(self, name):
return name in self.__class__.__slots__
#
def SetOnlySlot(self, name, value):
if not self.IsInSlots(name): return
self.__setattr__(name, value)
#
def UpdateFromDict(self, d):
for key,value in d.items():
self.SetOnlySlot(key, value)
#
def Update(self, *args0, **args1):
for a in args0: self.UpdateFromDict(a)
self.UpdateFromDict(args1)
#
def SlotsDict(self):
d = {}
for name in self.Slots():
try:
value = self.__getattribute__(name)
except AttributeError:
pass
else:
d[name] = value
return d
#
def has_key(self, k):
return self.SlotsDict().has_key(k)
#
def keys(self):
return self.SlotsDict().keys()
#
def values(self):
return self.SlotsDict().values()
#
def items(self):
return self.SlotsDict().items()
#
def copy(self):
return copy.copy(self)
#
def update(self, d):
self.UpdateFromDict(d)
#
def get(self, key, default=None):
return self.SlotsDict().get(key, default)
More information about the Python-list
mailing list