__getitem__ method on (meta)classes

Steven Bethard steven.bethard at gmail.com
Wed Mar 16 15:54:24 EST 2005


Ron Garret wrote:
> Using a metaclass allows you to distinguish Fred the plumber from Fred 
> the electrician.  But that may or may not be what one actually wants.

Not sure what you mean here.  The non metaclass solution still has 
separate enum.item objects for each new enum.  Consider your implementation:

py> def enum(vals):
...     class enum(object):
...         class __metaclass__(type):
...             def __getitem__(self, index):
...                 return self.vals[index]
...         def __init__(self, val):
...             try:
...                 self.val = type(self).vals.index(val)
...             except:
...                raise TypeError('%s is not a valid %s' %
...                                (val, type(self).__name__))
...     enum.vals = vals
...     return enum
...
py> plumbers = enum(['Fred','John','Bill'])
py> electricians = enum(['Fred','Jake','Lester'])
py> plumbers[0] == electricians[0]
True
py> plumbers('Fred') == electricians('Fred')
False
py> plumbers[0], electricians[0]
('Fred', 'Fred')
py> plumbers('Fred'), electricians('Fred')
(<__main__.enum object at 0x0115D530>, <__main__.enum object at 0x01162D50>)

Note that your implementation conflates plumbers[0] and electricians[0] 
(because your __getitem__ returns the string, not an enum object).  Not 
sure if this is the intended behavior, but it seems a little weird to 
me.  OTOH, plumbers('Fred') and electricians('Fred') are not conflated.

Now consider my implementation:

py> class enum(object):
...     class item(object):
...         def __init__(self, val):
...             self.val = val
...     def __init__(self, vals):
...         self.items = [type(self).item(val) for val in vals]
...         self._val_item_map = dict(zip(vals, self.items))
...     def __call__(self, val):
...         try:
...             return self._val_item_map[val]
...         except KeyError:
...             raise TypeError('%s is not a valid %s'
...                             (val, type(self)))
...     def __getitem__(self, index):
...         return self.items[index]
...     def __iter__(self):
...         return iter(self.items)
...
py> plumbers = enum(['Fred','John','Bill'])
py> electricians = enum(['Fred','Jake','Lester'])
py> plumbers[0] == electricians[0]
False
py> plumbers('Fred') == electricians('Fred')
False
py> plumbers[0], electricians[0]
(<__main__.item object at 0x011627F0>, <__main__.item object at 0x011883B0>)
py> plumbers('Fred'), electricians('Fred')
(<__main__.item object at 0x011627F0>, <__main__.item object at 0x011883B0>)

Note that Fred the plumber and Fred the electrician always compare as 
inequal (using either __call__ or __getitem__).  Isn't this "allowing 
you to distinguish Fred the plumber from Fred the electrician"?

STeVe



More information about the Python-list mailing list