On Mon, 16 Jan 2006 21:58:26 +1100, Steven D'Aprano <[EMAIL PROTECTED]> 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 -- http://mail.python.org/mailman/listinfo/python-list