Is 'everything' a refrence or isn't it?

Steven D'Aprano steve at REMOVETHIScyber.com.au
Mon Jan 16 17:24:37 EST 2006


On Mon, 16 Jan 2006 21:18:35 +0000, Bengt Richter wrote:

> On Mon, 16 Jan 2006 21:58:26 +1100, Steven D'Aprano <steve at REMOVETHIScyber.com.au> wrote:
> 
>>On Mon, 16 Jan 2006 10:34:40 +0000, Bengt Richter wrote:
>>
>>>  >>> class A:
>>>  ...     def __getattr__(self, attr): print 'A().%s'%attr; raise AttributeError
>>>  ...
>>>  >>> class B:
>>>  ...     def __getattr__(self, attr): print 'B().%s'%attr; raise AttributeError
>>>  ...
>>>  >>> A()==B()
>>>  A().__eq__
>>>  B().__eq__
>>>  B().__eq__
>>>  A().__eq__
>>>  A().__coerce__
>>>  B().__coerce__
>>>  A().__cmp__
>>>  B().__cmp__
>>>  False
>>
>>Why are A().__eq__ and B().__eq__ both being called twice?
>>
> I imagine it's trying the calls with args swapped or something like that.
> Want to write a test and see? (Don't hold your breath if you're waiting for me to do it ;-)

You already wrote a test. I can't think of any test I can write which
would give more information than yours. I'd like a test where I can see
the arguments which Python would apply to each method call, but I can't
think of any way to get those arguments inside the __getattr__ method.
Perhaps I'm not thinking hard enough.

(Actually writing __eq__ methods would defeat the purpose.)

There aren't that many possibilities. We can predict the other argument
from each call: if you call a method of A, the argument must be B and vice
versa. So it looks like Python is making the following calls:

A().__eq__(B)
B().__eq__(A)
B().__eq__(A)
A().__eq__(B)

followed by the unproblematic calls to __coerce__ and __cmp__.

What puzzles me is that after trying B.__eq__(A), it tries it again
immediately. It only calls coerce and cmp once with each set of args. What
am I missing?



-- 
Steven.




More information about the Python-list mailing list