Impossible to change methods with special names of instances of new-style classes?

Joseph Barillari python at barillari.org
Tue Jul 8 17:56:45 EDT 2008


Hi python-list,

I've just started using new-style classes and am a bit confused as to
why I can't seem to alter methods with special names
(__call__, etc.) of new-style class instances. In other words, I
can do this:

>>> class Z:
...     pass
...
>>> z = Z()
>>> z.__call__ = lambda : 33
>>> z()
33

But apparently I can't do this:

>>> class NZ(object):
...     pass
...
>>> nz = NZ()
>>> nz.__call__ = lambda : 33
>>> nz()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NZ' object is not callable


I found this post from Bengt Richter three years ago which addressed a
related problem:

http://mail.python.org/pipermail/python-list/2005-July/332961.html
   
   >Apparently the issue, as stated implicitly or explicitly by most of  
   >you, is that new-style class instances essentially defer their magic  
   >methods to the class's static versions of same. This is good to know :)

   Actually, it's not just the "magic" methods. If you have an
   instance a of a newstyle class A, any attribute lookup a.attr will
   undergo the same search first to see if attr is a descriptor
   object, and if not, *then* to look in the instance attribute
   directory. But the descriptor search doesn't start in
   inst.__dict__, it goes through the chain of classes and base
   classes provided by type(inst).mro(), which starts in
   type(inst). And for our class A instance a, type(a) will be A, so
   the search for a.attr starts there. Same applies to a.__str__. This
   ensures that all instances of the same class will share the same
   methods. The way a method, which is just a class variable with a
   function as its value, gets to be a callable bound method, is the
   same as any attribute lookup looking for a descriptor with a
   __get__ method (which a function also has, for this purpose).  If
   the descriptor doesn't have a __set__ method as well, then an
   instance attribute takes priority. If there is a __set__ method,
   and instance attribute can't shadow the attribute name, and the
   descriptor __get__ method takes precedence. Unshadowed, a method
   search looks something like

    cbm = ((base for base in type(inst).mro() if 'attr' in base.__dict__)
          .next().__dict__['attr'].__get__(inst, type(inst)))

    if this doesn't succeed and meet the __set__ vs shadowing logic, then you get
    the instance attribute per se.

...but if I understand correctly, this suggests that if the runtime
can't find the attribute in the chain of classes and base classes, it
will look in the instance dictionary. The behavior of NZ above suggests that
it the runtime is _not_ doing that for __call__ as it would for a non-special name:

>>> class NZ(object):
...     pass
... 
>>> nz = NZ()
>>> nz.f = lambda : 42
>>> nz.f()
42

My question is: did something about the way the special method names are 
implemented change for new-style classes? 

best, and thanks in advance,

Joe



More information about the Python-list mailing list