[Mark]
> inputs with a special real or imaginary component. On balance, I'd
> support making complex('nan + nan*j') do the right thing.
Having thought about this a bit more, I take this back. Some reasons are
given below.
[David]
> - complex(repr(..)) roundtrip should work, whatever the value of complex
is
I disagree. *Why* do you think it should work? It fails for many other
types:
>>> def roundtrip(x): return type(x)(repr(x))
...
>>> roundtrip("abc")
"'abc'"
>>> roundtrip([1,2,3])
['[', '1', ',', ' ', '2', ',', ' ', '3', ']']
>>> roundtrip((1,))
('(', '1', ',', ')')
>>> roundtrip(Fraction(1, 2))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in roundtrip
File "/Users/dickinsm/python_source/trunk/Lib/fractions.py", line 73, in
__new__
raise ValueError('Invalid literal for Fraction: %r' % input)
ValueError: Invalid literal for Fraction: 'Fraction(1, 2)'
>>> roundtrip(Decimal(1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in roundtrip
File "/Users/dickinsm/python_source/trunk/Lib/decimal.py", line 545, in
__new__
"Invalid literal for Decimal: %r" % value)
File "/Users/dickinsm/python_source/trunk/Lib/decimal.py", line 3721, in
_raise_error
raise error(explanation)
decimal.InvalidOperation: Invalid literal for Decimal: "Decimal('1')"
In general, type(repr(x)) == x only works for simple types (ints, floats),
not compound types like lists, strings, tuples, ... I think it's
reasonable to regard complex as such a compound type.
There *is* a general Python guideline that eval(repr(x)) == x should work
where possible. Note that this fails even for floats:
>>> eval(repr(float('nan')))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'nan' is not defined
The *real* problem here is that repr(complex) is a mess when it comes to
niceties like signed zeros, infinities and nans:
>>> complex(-0., 0.) # throws away sign of 0 on real part
0j
>>> eval(repr(complex(2., -0.))) # throws away sign on imag. part
(2+0j)
>>> nan = float('nan')
>>> complex(0, nan)
nan*j
>>> nan*j # can't even eval this...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'j' is not defined
>>> nan*1j # not much better: real part should be 0, not nan
(nan+nan*j)
>>> inf = float('inf')
>>> inf*1j # ouch: nan in real part!
(nan+inf*j)
I think the *right* solution is to define repr of a complex number
z to be:
"complex(%r, %r)" % (z.real, z.imag)
but that's not possible before the mythical, compatibility-breaking,
Python 4.0. And even then your desired complex(repr(z)) roundtripping
wouldn't work, though eval(repr(z)) would.
While we're daydreaming, another possibility is to follow C99's lead, and
introduce a type of 'imaginary' numbers, and make 1j be an imaginary
literal rather than a complex literal. That solves some of the above
eval(repr(.)) problems. Again, I don't see how this could happen before
4.0, and I'm not even sure that it's desirable.
In the circumstances, repr does the best it can, which is to output a
whole expression which more-or-less describes the given complex number,
and will usually eval back to the right thing. I think it's not the
business of the complex() constructor to parse such expressions.
To summarize: it's a mess. I'd recommend that you and/or numpy don't use
repr for roundtrip-capable conversions to string. Instead, output the
real and imaginary parts separately, and use float-from-string and the
complex-from-pair-of-floats constructors to reconstruct. |