[Python-bugs-list] [ python-Bugs-643841 ] New class special method lookup change

noreply@sourceforge.net noreply@sourceforge.net
Mon, 25 Nov 2002 20:25:04 -0800


Bugs item #643841, was opened at 2002-11-25 18:37
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=643841&group_id=5470

Category: None
Group: None
Status: Open
Resolution: None
Priority: 5
Submitted By: Terry J. Reedy (tjreedy)
Assigned to: Nobody/Anonymous (nobody)
Summary: New class special method lookup change

Initial Comment:

The lookup of special methods invoked implicitly by 
syntax other than explicit instance.attribute changed 
to *not* use __gettattr__ when normal lookup failed.  
This is contrary to docs, which consistently say 
__getattr__ is unchanged.  New special method 
__getattribute__ is also bypassed, contrary to 
implication of doc-essay.

This was reported on c.l.p by Jan Decaluwe using 
2.2.2 on Red Hat Linux.  On Win98, 2.2.1, I get same 
behavior (I added test of __getattribute__):

class Iold:
  def __init__(self,ob):
    self.ob = ob
  def __getattr__(self,name):
    return getattr(self.ob,name)

class Inew(object):
  def __init__(self,ob):
    self.ob = ob
  def __getattr__(self,name):
    return getattr(self.ob,name)

a = Iold(1) #2
b = Inew(1) #2
a.__add__(1) #2
b.__add__(1) #2
a+1 #2
b+1 #error
#TypeError: unsupported operand types for +: 'Inew' 
and 'int'
Inew.__getattribute__ = Inew.__getattr__
b+1 #same error, no loop
#TypeError: unsupported operand types for +: 'Inew' 
and 'int'

b.__add__(1) # WARNING starts 'infinite' loop

def _(self,other): print 'hello'

Inew.__add__ = _
b+1 #prints 'hello', __getattribute__ bypassed.

http://python.org/2.2/descrintro.html says:
"Note that while in general operator overloading 
works just as for classic classes, there are some 
differences. (The biggest one is the lack of support for 
__coerce__; new-style classes should always use the 
new-style numeric API, which passes the other 
operand uncoerced to the __add__ and __radd__ 
methods, etc.) "

Was lookup change meant to be one of differences?

"There's a new way of overriding attribute access. The 
__getattr__ hook, if defined, works the same way as it 
does for classic classes: it is only called if the regular 
way of searching for the attribute doesn't find it."

But it is different.

 "But you can now also override __getattribute__, a 
new operation that is called for all attribute 
references." 

Except for implicit special methods.

I did not classify discrepancy because I don't know 
whether interpreter or docs are off.






----------------------------------------------------------------------

>Comment By: Terry J. Reedy (tjreedy)
Date: 2002-11-25 23:25

Message:
Logged In: YES 
user_id=593130

Print-style 'debugging' output provided by Bengt Richter in 
a follow-up in the c.l.p. thread "Issue with new-style 
classes and operators" showed that 'a+1' worked because 
of a __getattr__ call getting '__coerce__' (rather 
than '__add__') and that 'b+1' did not trigger such a call.  
So I presume the quoted parenthesized statement about 
__coerce__ and 'new-style numeric API' was meant to 
explain as least this part of the change in behavior.  
However, it is still not clear to me, even after reading the 
development (2.3a) version of the ref manual, why failure 
to find '__add__' in 'the usual places' (to quote RefMan 
3.3.2 __getattr__ entry) does not trigger a call to 
__getattr__, nor why the initial attempt to find it did not 
trigger __getattribute__.  The sentence 'For objects x and y, 
first x.__op__(y) is tried' (3.3.7) implies to me that there is 
an attempt to find __op__ as an attribute of x.  Unless I 
missed something I should have found, a bit more 
clarification might be usefully added.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=643841&group_id=5470