[Python-Dev] return type of __complex__

Nick Coghlan ncoghlan at gmail.com
Sun Oct 21 04:57:31 CEST 2012


On Sun, Oct 21, 2012 at 11:53 AM, Steven D'Aprano <steve at pearwood.info> wrote:
> On 21/10/12 06:28, Tres Seaver wrote:
>>
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> On 10/19/2012 07:35 PM, Greg Ewing wrote:
>>>
>>> Antonio Cuni wrote:
>>>>
>>>> Traceback (most recent call last): File "<stdin>", line 1, in
>>>> <module>  TypeError: __complex__ should return a complex object
>>>>
>>>> i.e., the complex constructor does not check that __complex__
>>>> returns an actual complex, while the cmath functions do.
>>>
>>>
>>> Looks to me like cmath is being excessively finicky here. Why
>>> shouldn't a float be usable in *any* context expecting a complex?
>>
>>
>> Exactly:  float is perfectly Liskov-substituable for complex;  only
>> applications which do explicit type sniffing can tell the difference,
>> which makes the sniffing bogus.
>
>
>
> But float is not *numerically* substitutable for complex, which is why
> type-sniffing is not bogus at all. If you have an application which
> assumes numeric quantities represent real values, then you need to
> distinguish between real-valued and complex-valued arithmetic, and
> treating floats as implicitly complex is the wrong thing to do.
>
> Since most applications are based on real-values, implicit promotion to
> complex is in my opinion an anti-feature.
>
> Python 2.x legitimately distinguished between floats and complex, e.g.:
>
> py> (-100.0)**0.5
>
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> ValueError: negative number cannot be raised to a fractional power
>
> If you wanted a complex result, you can explicitly ask for one:
>
> py> (-100.0+0j)**0.5
> (6.123031769111886e-16+10j)
>
>
> I see that behaviour is changed in Python 3. Was this discussed before
> being changed? I see a single sample docstring buried in PEP 3141 that:
>
> """a**b; should promote to float or complex when necessary."""
>
> but I can't find any discussion of the consequences of this for the
> majority of users who would be surprised by the unexpected appearance
> of a "j" inside their numbers.

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

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).

Cheers,
Nick.

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


More information about the Python-Dev mailing list