New style classes and operator methods

I think I've found a small flaw in the implementation of binary operator methods for new-style Python classes. If the left and right operands are of the same class, and the class implements a right operand method but not a left operand method, the right operand method is not called. Instead, two attempts are made to call the left operand method. I'm surmising this is because both calls are funnelled through the same C-level method, which is using the types of the operands to decide whether to call the left or right Python methods. I suppose this isn't really a serious problem, since it's easily worked around by always defining at least a left operand method. But I thought I'd point it out anyway. The following example illustrates the problem: class NewStyleSpam(object): def __add__(self, other): print "NewStyleSpam.__add__", self, other return NotImplemented def __radd__(self, other): print "NewStyleSpam.__radd__", self, other return 42 x1 = NewStyleSpam() x2 = NewStyleSpam() print x1 + x2 which produces: NewStyleSpam.__add__ <__main__.NewStyleSpam object at 0x4019062c> <__main__.NewStyleSpam object at 0x4019056c> NewStyleSpam.__add__ <__main__.NewStyleSpam object at 0x4019062c> <__main__.NewStyleSpam object at 0x4019056c> Traceback (most recent call last): File "/home/cosc/staff/research/greg/tmp/foo.py", line 27, in ? print x1 + x2 TypeError: unsupported operand type(s) for +: 'NewStyleSpam' and 'NewStyleSpam' Old-style classes, on the other hand, work as expected: class OldStyleSpam: def __add__(self, other): print "OldStyleSpam.__add__", self, other return NotImplemented def __radd__(self, other): print "OldStyleSpam.__radd__", self, other return 42 y1 = OldStyleSpam() y2 = OldStyleSpam() print y1 + y2 produces: OldStyleSpam.__add__ <__main__.OldStyleSpam instance at 0x4019054c> <__main__.OldStyleSpam instance at 0x401901ec> OldStyleSpam.__radd__ <__main__.OldStyleSpam instance at 0x401901ec> <__main__.OldStyleSpam instance at 0x4019054c> 42 -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+

Hi Greg, On Fri, Apr 08, 2005 at 05:03:42PM +1200, Greg Ewing wrote:
If the left and right operands are of the same class, and the class implements a right operand method but not a left operand method, the right operand method is not called. Instead, two attempts are made to call the left operand method.
This is not a general rule. The rule is that if both elements are of the same class, only the non-reversed method is ever called. The confusing bit is about having it called twice. Funnily enough, this only occurs for some operators (I think only add and mul). The reason is that internally, the C core distinguishes about number adding vs sequence concatenation, and number multiplying vs sequence repetition. So __add__() and __mul__() are called twice: once as a numeric computation and as a sequence operation... Could be fixed with more strange special cases in abstract.c, but I'm not sure it's worth it. Armin
participants (2)
-
Armin Rigo
-
Greg Ewing