Mark, did you do anything with my reply? On Mon, Mar 5, 2012 at 10:41 AM, Guido van Rossum <gu...@python.org> wrote: > On Mon, Mar 5, 2012 at 4:41 AM, Mark Shannon <m...@hotpy.org> wrote: >> Comparing two objects (of the same type for simplicity) >> involves a three stage lookup: >> The class has the operator C.__eq__ >> It can be applied to operator (descriptor protocol): C().__eq__ >> and it produces a result: C().__eq__(C()) >> >> Exceptions can be raised in all 3 phases, >> but an exception in the first phase is not really an error, >> its just says the operation is not supported. >> E.g. >> >> class C: pass >> >> C() == C() is False, rather than raising an Exception. >> >> If an exception is raised in the 3rd stage, then it is propogated, >> as follows: >> >> class C: >> def __eq__(self, other): >> raise Exception("I'm incomparable") >> >> C() == C() raises an exception >> >> However, if an exception is raised in the second phase (descriptor) >> then it is silenced: >> >> def no_eq(self): >> raise Exception("I'm incomparable") >> >> class C: >> __eq__ = property(no_eq) >> >> C() == C() is False. >> >> But should it raise an exception? >> >> The behaviour for arithmetic is different. >> >> def no_add(self): >> raise Exception("I don't add up") >> >> class C: >> __add__ = property(no_add) >> >> C() + C() raises an exception. >> >> So what is the "correct" behaviour? >> It is my opinion that comparisons should behave like arithmetic >> and raise an exception. > > I think you're probably right. This is one of those edge cases that > are so rare (and always considered a bug in the user code) that we > didn't define carefully what should happen. There are probably some > implementation-specific reasons why it was done this way (comparisons > use a very different code path from regular binary operators) but that > doesn't sound like a very good reason. > > OTOH there *is* a difference: as you say, C() == C() is False when the > class doesn't define __eq__, whereas C() + C() raises an exception if > it doesn't define __add__. Still, this is more likely to have favored > the wrong outcome for (2) by accident than by design. > > You'll have to dig through the CPython implementation and find out > exactly what code needs to be changed before I could be sure though -- > sometimes seeing the code jogs my memory. > > But I think of x==y as roughly equivalent to > > r = NotImplemented > if hasattr(x, '__eq__'): > r = x.__eq__(y) > if r is NotImplemented and hasattr(y, '__eq__'): > r = y.__eq__(x) > if r is NotImplemented: > r = False > > which would certainly suggest that (2) should raise an exception. A > possibility is that the code looking for the __eq__ attribute > suppresses *all* exceptions instead of just AttributeError. If you > change no_eq() to return 42, for example, the comparison raises the > much more reasonable TypeError: 'int' object is not callable. > > -- > --Guido van Rossum (python.org/~guido)
-- --Guido van Rossum (python.org/~guido) _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com