setattr question

Peter Otten __peter__ at web.de
Thu Feb 19 18:38:46 CET 2009


TP wrote:

> Hi everybody,
> 
> I try to make a "link" (or shortcut, if you want) so that len(b_instance)
> computes in fact len(a) (see the code below). I could write a method
> __len__ to b, but I wonder if it is possible to make it with a
> setattr/getattr trick, as I do below.
> 
> Thanks in advance,
> 
> Julien
> 
> ######################
> class b( object ):
> 
>     def __init__( self ):
> 
>         super( b, self ).__init__()
> 
> a = [5,4,7]
> b_instance = b()
> 
> setattr( b_instance, "__len__", getattr( a, "__len__") )

Invoking setattr() or getattr() with a constant name is bogus. The above can
be written as

b_instance.__len__ = a.__len__

> print len( a )
> print id( a.__len__ )
> print hasattr( b_instance, "__len__" )
> print id( b.__len__ )
> print len( b_instance )
> ########################
> 
> I obtain:
> $ p test_setattr.py
> 3
> 3083822540
> True
> Traceback (most recent call last):
>   File "test_setattr.py", line 14, in <module>
>     print id( b.__len__ )
> AttributeError: type object 'b' has no attribute '__len__'
>         Command failure: error 1 !
> 

__special__ methods in newstyle classes are looked up in the class, not the
instance: 

>>> class B(object): pass
...
>>> items = [1,2,3]
>>> b = B()
>>> len(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'B' has no len()
>>> B.__len__ = items.__len__
>>> len(b)
3

Now that doesn't make much sense because all instances of B now share the
same length. If you want a useful per-instance length function you have to
delegate:

>>> class B(object):
...     def __len__(self): return self._len()
...
>>> a = B()
>>> b = B()
>>> a._len = [1,2,3].__len__
>>> b._len = [].__len__
>>> len(a), len(b)
(3, 0)

Peter




More information about the Python-list mailing list