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

Bengt Richter bokr at oz.net
Mon Jan 16 19:51:52 EST 2006


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?
>
Looks like it has to do with trying stuff with arguments switched?
This shows call and argumenst to method for whichever attribute access
is allowed to succeed after a count of failures...

 >>> def test():
 ...     global trial, which
 ...     for which in xrange(9):
 ...         print '\nwhich: %s'%which
 ...         trial = 0
 ...         A()==B()
 ...
 >>> def nameof(x):return type(x).__getattribute__(x, '__class__').__name__
 ...
 >>> def __eq__(x, y):
 ...     print '__eq__(%s(), %s())'%(nameof(x), nameof(y)); return False
 ...
 >>> def __cmp__(x, y):
 ...     print '__cmp__(%s(), %s())'%(nameof(x), nameof(y)); return 0
 ...
 >>> def __coerce__(x, y):
 ...     print '__coerce__(%s(), %s())'%(nameof(x), nameof(y)); return None
 ...
 >>> class A:
 ...     def __getattr__(self, attr):
 ...         global trial
 ...         print '%s: A().%s'%(trial, attr)
 ...         if trial!=which: trial+=1; raise AttributeError
 ...         return globals()[attr].__get__(self, type(self))
 ...
 >>> class B:
 ...     def __getattr__(self, attr):
 ...         global trial
 ...         print '%s: B().%s'%(trial, attr)
 ...         if trial!=which: trial+=1; raise AttributeError
 ...         return globals()[attr].__get__(self, type(self))
 ...
 >>> test()
 
 which: 0
 0: A().__eq__
 __eq__(A(), B())
 
 which: 1
 0: A().__eq__
 1: B().__eq__
 __eq__(B(), A())
 
 which: 2
 0: A().__eq__
 1: B().__eq__
 2: B().__eq__
 __eq__(B(), A())
 
 which: 3
 0: A().__eq__
 1: B().__eq__
 2: B().__eq__
 3: A().__eq__
 __eq__(A(), B())
 
 which: 4
 0: A().__eq__
 1: B().__eq__
 2: B().__eq__
 3: A().__eq__
 4: A().__coerce__
 __coerce__(A(), B())
 4: B().__coerce__
 __coerce__(B(), A())
 4: A().__cmp__
 __cmp__(A(), B())
 
 which: 5
 0: A().__eq__
 1: B().__eq__
 2: B().__eq__
 3: A().__eq__
 4: A().__coerce__
 5: B().__coerce__
 __coerce__(B(), A())
 5: A().__cmp__
 __cmp__(A(), B())
 
 which: 6
 0: A().__eq__
 1: B().__eq__
 2: B().__eq__
 3: A().__eq__
 4: A().__coerce__
 5: B().__coerce__
 6: A().__cmp__
 __cmp__(A(), B())
 
 which: 7
 0: A().__eq__
 1: B().__eq__
 2: B().__eq__
 3: A().__eq__
 4: A().__coerce__
 5: B().__coerce__
 6: A().__cmp__
 7: B().__cmp__
 __cmp__(B(), A())
 
 which: 8
 0: A().__eq__
 1: B().__eq__
 2: B().__eq__
 3: A().__eq__
 4: A().__coerce__
 5: B().__coerce__
 6: A().__cmp__
 7: B().__cmp__
 >>>
 
Regards,
Bengt Richter



More information about the Python-list mailing list