Question about accessing class-attributes.

Michele Simionato mis6 at pitt.edu
Tue Apr 29 23:21:56 CEST 2003


"Bjorn Pettersen" <BPettersen at NAREX.com> wrote in message news:<mailman.1051637056.20383.python-list at python.org>...
> > From: Alex Martelli [mailto:aleax at aleax.it] 
>  [...]
> Here's the case I'm confused about:
> 
> >>> class meta(type):
> ...   def   getattr  (cls, name):
> ...     if name == '  len  ':
> ...        print "meta.  getattr  ('  len  ')"
> ...        return lambda: 42
> ...     else:
> ...        print 'meta.  getattr  ', name
> ...        return name
> ...
> >>> class S(object):
> ...     metaclass   = meta
> ...
> >>> S.  len  ()
> meta.  getattr  ('  len  ')
> 42
> >>> len(S)
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> TypeError: len() of unsized object
> >>>
> 
> I was told that special method "foo(x, arg)" was implemented as
> "type(x).  foo  (x, arg)", which doesn't seem to be the case always...
> Compare:
> 
> >>> class meta(type):
> ...   def   len  (cls):
> ...     return 42
> ...
> >>> class S(object):
> ...     metaclass   = meta
> ...
> >>> S.  len  ()
>  42
> >>> len(S)
>  42
> >>>
> 
> So, it looks like it's looking up   len   in the metaclass, but not
> falling back on   getattr   when it isn't there? 

I am sure Alex is going to answer, but since you asked me a related
question in another thread ...

Finally, now I see where is the source of the confusion:

len(S) fails because meta.__len__ is NOT defined in
you first example. The point is that __getattr__ works on instances of
meta, NOT on meta itself, therefore S.__len__ is recognized thanks
to __getattr__, but NON meta.__len__
In order to recognize meta.__len__ you must define __getattr__ on the
metaclass of meta, i.e. the meta-metaclass of S:

class metameta(type):
    def __getattr__(cls, name):
        if name == '__len__':
            print "metameta.__getattr__('  len  ')"
            return lambda cls: 42
        else:
            print 'metameta.__getattr__', name
            return name

class meta(type):
    __metaclass__=metameta
    
class S(object):
    __metaclass__ = meta

print type(S).__len__(S) 

with output

metameta.__getattr__('  len  ')
42


I must say, however, that len(S) is not *literally* type(S).__len__(S):

print len(S)

Traceback (most recent call last):
  File "<stdin>", line 18, in ?
TypeError: len() of unsized object

I think Python looks if __len__ is defined in the meta-class and
if not, it does raise an exception. It does not know that there is
a __getattr__ in the meta-metaclass, unless you invoke the metaclass literally
as in type(S).__len__(S).

I did not understood your point in the other thread, I didn't imagine
you where thinking about meta-metaclasses. As you see, there are 
situations where they may be useful, i.e. in the customization of 
metaclasses, but most people don't think at this level yet ;)

Cheers,

                       Michele




More information about the Python-list mailing list