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