[Python-ideas] Should this be considered a bug?

Nick Coghlan ncoghlan at gmail.com
Mon Oct 31 00:46:42 CET 2011


On Mon, Oct 31, 2011 at 9:15 AM, Mike Meyer <mwm at mired.org> wrote:
>> Commutativity is an important expected property for addition and
>> multiplication. Even NumPy's arrays respect that by using those
>> operations for the element-wise equivalents - they use a separate
>> method for matrix multiplication (which is not commutative by
>> definition).
>
> I agree. And if lists were commutative under addition, I'd say that
> was sufficient reason not to do this. But they aren't.

Yeah, I was thinking in terms of type inference, but writing in terms
of values. I should have stuck with my original examples, which showed
the type inference rather than using specific instances.

Basically, the design principle at work here is "the type of the
result of a binary operation should not depend on the order of the
operands". It has its roots in commutativity, but is not commutativity
as such (since that is about values, not types).

This principle drives lots of aspects of Python's implicit type
conversion design. For example:

1. The left hand operand is typically given the first go at handling
the operation, but is expected to return NotImplemented if it doesn't
recognise the other operand
2. The right hand operand is given first go in the case where it is an
instance of a *subclass* of the type of the left hand operand, thus
allowing subclasses to consistently override the behaviour of the
parent class
3. Most types (with the notable exception of numeric types) will only
permit binary operations with other instances of the same type. For
numeric types, the coercion is arranged so that the type of the result
remains independent of the order of the operands.

I did find an unfortunate case where Python 3 violates this design
principle - bytes and bytearray objects accept any object that
implements the buffer interface as the other operand, even in the
__add__ case. This leads to the following asymmetries:

>>> b'' + bytearray()
b''
>>> b'' + memoryview(b'')
b''
>>> bytearray() + b''
bytearray(b'')
>>> bytearray() + memoryview(b'')
bytearray(b'')
>>> memoryview(b'') + b''
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'memoryview' and 'bytes'
>>> memoryview(b'') + bytearray(b'')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'memoryview' and 'bytearray'

Now, the latter two cases are due to the problem I mentioned earlier
where returning NotImplemented from sq_concat or sq_repeat doesn't
work properly, but the bytes and bytearray interaction is exactly the
kind of type asymmetry this guideline is intended to prevent.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia



More information about the Python-ideas mailing list