[Python-Dev] return type of __complex__

Devin Jeanpierre jeanpierreda at gmail.com
Sun Oct 21 07:06:08 CEST 2012


On Sat, Oct 20, 2012 at 10:57 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> PEP 3141 is indeed the driver for these changes, and it's based on the
> Python 3.x numeric tower consisting of strict supersets: Complex >
> Real > Rational > Integral

Pedant mode: That numeric tower is wrong as it applies to Python -- we
have some rational types that can represent some numbers that can't be
represented by our complex and """real""" types.

    >>> int(float(10**100)) == 10**100
    False

(Also, floats aren't reals and no computer can store any number that
is not rational and we should stop pretending they can. (Complex
numbers get a free pass because "complex numbers with rational real
and imaginary parts" is not a memorable name for a type.))

*Pedant mode deactivated*

> If an operation at one level of the tower produces a result in one of
> the larger supersets, then *that's what it will do* rather than
> throwing TypeError. int / int promoting to float is one example, as is
> raising a negative number to a fractional power promoting to complex.
>
> The general philosophy is described in
> http://www.python.org/dev/peps/pep-3141/#implementing-the-arithmetic-operations
>
> It sounds like cmath (or, more specifically, the "D" conversion code)
> missed out on the associated updates).

No, no no. The return type of conversion methods has nothing to do
with the interoperability of types in arithmetic. If it did there
would've been a systematic purging of old behaviors in these
conversion functions, and there evidently hasn't been because float(),
cmath, and math all behave "wrong", and those are collectively fairly
hard to miss.

Since float(), cmath, and math all behave the same, I'd assert that
it's complex() (and int()) that is weird and unusual.

>>> class A:
...     def __complex__(self):
...             return 1
...     def __float__(self):
...             return 1
...
>>> complex(A())
(1+0j)
>>> float(A())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __float__ returned non-float (type int)
>>> cmath.sqrt(A())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __complex__ should return a complex object
>>> math.sqrt(A())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: nb_float should return float object
>>>

-- Devin


More information about the Python-Dev mailing list