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

  • Thread starter Joseph Barillari
  • Start date
J

Joseph Barillari

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:
.... pass
....33

But apparently I can't do this:
.... pass
....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:
.... pass
.... 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
 
C

cokofreedom

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

Traceback (most recent call last):
File "<pyshell#30>", line 1, in <module>
testtwo()
TypeError: 'new' object is not callable
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
old.__call__
AttributeError: class old has no attribute '__call__'['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'__weakref__']
dir(testone) ['__call__', '__doc__', '__module__']
dir(new)
['__class__', '__delattr__', '__dict__', '__doc__',
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'__weakref__']['__doc__', '__module__']

I don't see __call__ in either class structures, but for new style
classes it is a wrapper and for old it is nothing. Not sure if that
helps, but this is rather over my head.
 
S

samwyse

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

Just off the top of my head, I'd guess that it's due to classes
already having a default __call__ method, used when you instatiate.
Remember, the Python compiler doesn't know the difference between
this:
a = MyClass
instance = a()
and this:
a = myFunc
result = a()
 
T

Terry Reedy

I believe the difference is that for new-style classes, when special
methods are called 'behind the scenes' to implement built-in syntax and
methods, they are looked up directly on the class instead of first on
the instance. Note that functions attached to instances are *not*
methods and do not get combined with the instance as a bound method.
 
B

Bruno Desthuilliers

samwyse a écrit :
Just off the top of my head, I'd guess that it's due to classes
already having a default __call__ method,
['__setattr__', '__reduce_ex__', '__new__', '__reduce__', '__str__',
'__getattribute__', '__class__', '__delattr__', '__repr__', '__hash__',
'__doc__', '__init__']

No __call__ method here.
used when you instatiate.

The __call__ method used to instanciate a class is actually the
metaclass __call__ method.
.... def __call__(self, *args, **kw):
.... print "pikaboo"
.... return type.__call__(self, *args, **kw)
........ __metaclass__ = MyType
....
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top