__getitem__ method on (meta)classes

Bengt Richter bokr at oz.net
Mon Mar 14 21:48:58 EST 2005


On 14 Mar 2005 17:43:53 -0800, ron at flownet.com wrote:

>
>Why doesn't this work?
>
>>>> def foo(lst):
>...   class baz(object):
>...     def __getitem__(cls, idx): return cls.lst[idx]
>...     __getitem__=classmethod(__getitem__)
>...   baz.lst = lst
>...   return baz
>...
>>>> f = foo([1,2,3])
>>>> f[0]
>Traceback (most recent call last):
>  File "<stdin>", line 1, in ?
>TypeError: unsubscriptable object
>>>> f.__getitem__(0)
>1
>>>>
>
>
>I thought x[y] and x.__getitem__(y) were supposed to always be
>synonymous.
Yes, but what was your "x"?
Note:

 >>> def foo(lst):
 ...     class baz(object):
 ...         def __getitem__(cls, idx): return cls.lst[idx]
 ...         __getitem__ = classmethod(__getitem__)
 ...     baz.lst = lst
 ...     return baz
 ...
 >>> f = foo([1,2,3])
 >>> f
 <class '__main__.baz'>

Your "x" was the baz *class*, and the baz *class* is not subscriptable *itself*,
even though it defines subscripting for its instances.
To be ordinarily subscriptable, type(f).__getitem__ would have to succeed, which it doesn't:

 >>> type(f)
 <type 'type'>
 >>> type(f).__getitem__
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 AttributeError: type object 'type' has no attribute '__getitem__'

However, a baz instance is different:

 >>> finst = f()
 >>> finst
 <__main__.baz object at 0x02EF168C>

Its type does have a __getitem__ attribute:

 >>> type(finst).__getitem__
 <bound method type.__getitem__ of <class '__main__.baz'>>

I think "bound method" is a bit of a misnomer for a classmethod, though
it is a method, and it is bound, just to the class instead of the instance.
(see below)

 >>> type(finst).__getitem__(0)
 1

Or straightforward indexing syntax:

 >>> finst[0], finst[1], finst[2]
 (1, 2, 3)

Contrast with the way an ordinary method repr's when you access it
via class and instance:

 >>> class C(object):
 ...    def ordinary_method(self): return 'Hi'
 ...
 >>> c=C()
 >>> C.ordinary_method
 <unbound method C.ordinary_method>
 >>> c.ordinary_method
 <bound method C.ordinary_method of <__main__.C object at 0x02EF164C>>
 >>> c.ordinary_method()
 'Hi'
 >>> C.ordinary_method
 <unbound method C.ordinary_method>
 >>> C.ordinary_method(c)
 'Hi'

Note the difference between ordinary and classmethod:

 >>> type(c).ordinary_method
 <unbound method C.ordinary_method>
 >>> type(finst).__getitem__
 <bound method type.__getitem__ of <class '__main__.baz'>>

BTW, I see a class factory, but no "(meta)"class per se.

Regards,
Bengt Richter



More information about the Python-list mailing list