msg269013 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2016-06-21 19:02 |
Look:
>>> complex('1-0j')
(1-0j)
>>> 1-0j
(1+0j)
Yes, I understand what's going on, and it's probably wrong / too much to expect 1-0j to work properly, but I'd really like the complex from string constructor to be consistent with that. Even more because (of course):
>>> import ast
>>> ast.literal_eval('1-0j')
(1+0j)
|
msg269014 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-06-21 19:27 |
This has been discussed in multiple issues before this one. Currently, `complex` from a string provides one of two ways to get a complex number with the correct signs for the real and imaginary parts; I'd hate to change that to give wrong results instead.
The other important property here is that `complex(repr(z))` recovers `z` for a complex number `z`. That would break with your suggested change.
Strong -1 from me.
|
msg269015 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-06-21 19:38 |
Related: #17336, #22548, #25839
|
msg269113 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2016-06-23 14:35 |
Breaking the repr invariant would be bad. Agree with rejection.
|
msg269144 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2016-06-23 21:32 |
Funny, I thought the "repr invariant" was exactly the opposite thing, that _eval_ (or literal_eval) of repr should give back the starting object. And that's what I intended to preserve here. It's obviously broken now.
Ok, alternate suggestion: can at least ast.literal_eval be fixed to work in the same way as complex constructor? Because it's not much of a "literal" otherwise...
|
msg269181 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2016-06-24 14:39 |
That's a good point; however the goal of the "repr invariant" is to be able to losslessly reproduce the object when possible. The fact that you have to use the complex constructor to do that is unfortunate, but is a consequence of the underlying problem. I suspect that literal_eval, on the other hand, should reproduce what the interpreter does, but since I think it already doesn't do that 100% (though I can't offhand remember what makes me think that) perhaps that is a possibility. I'll reopen the issue to discuss that.
|
msg269189 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-06-24 15:55 |
> I suspect that literal_eval, on the other hand, should reproduce what the interpreter does
I think that's going to be awkward to achieve without making the behaviour of literal_eval significantly less obvious and more DWIMmy. And I'm not convinced that `literal_eval` should follow the behaviour of the complex constructor rather than the behaviour of plain `eval`.
Of course, the "right" fix here is to change the complex repr entirely so that it looks like the compound object that it is rather than an eval-able expression:
>>> repr(1+2j)
complex(1.0, 2.0)
That would break backwards compatibility, but given the number of times complaints come up on this tracker, I'm beginning to think it might be worth it.
|
msg269233 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2016-06-25 12:22 |
Mark, I think it would be a great idea. It would be consistent with both "str is straightforward, repr is reproducible", and with the idea that (evalable) repr is almost always of the form `typename(arguments)`. It would also get rid of that "supefluous-looking" parentheses around the repr, and put them in the right place: a call. :-)
[ On the other hand, I started to think deeply about the reason why we cannot make 1-0j do the right thing, and I'm not so sure anymore. People usually say it's because we don't have separate imaginary type, but we don't need it: all we need is a separate _real_ type, and we have it: float.
When Python subtracts 0j from a float 1.0, there is no absolute imperative that it has to do it in the same way as subtracting 0j from a complex(1.0, 0.0). We _can_ make it so the result of the former is complex(1.0, -0.0), and result of the latter is complex(1.0, 0.0).
Of course, now even the imaginary complex numbers couldn't be outputed simply, and -0 real part should become -0.0, but it might be worth it. I understand it's enormously complicated though, and I'd be satisfied with a "normal" repr. Or a literal_eval that really understand complex numbers' repr. ]
|
msg269242 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-06-25 15:17 |
> People usually say it's because we don't have separate imaginary type, but we don't need it.
I think we do. Consider the case of something like -0 + 1j (the `repr` of complex(-0.0, 1.0)). That currently evaluates to `complex(0.0, 1.0)`, because the `-0.0` is combined with the `+0.0` real part of `1j`.
|
msg269270 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2016-06-26 01:05 |
Yes, but IMO that's a separate issue. And if complex analysis has taught me anything, it's that the sign of zero of .imag is much more important than the sign of zero of .real part (most elementary functions have branch cuts along real axis, where sign of .imag ensures continuity on both sides). Of course, having both would be even better, but having only this part is a good part of a good thing.
However, as I said, I know it's complicated. How about giving a "conventional" repr to complex? As far as I see, it's really not hard to implement - the only problem is backwards compatibility. But that was a problem when parentheses were added, too, right?
[ And there would be one more benefit: We could finally say goodbye to weird "names" (infj, nanj) in the repr. By analogy with float, this could just be complex('nan', '-inf') or whatever. ]
For what it's worth, I'm not sure we should try too hard to preserve complex(repr(z)) being z given isinstance(z, complex). For example, Fraction and Decimal don't have this property (while it does kinda hold for str instead of repr, and it would continue to kinda hold for str here). Yes, I know Fraction and Decimal aren't builtins and complex is, but I really think it's only because of syntax support for j-based literals.
|
msg269468 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2016-06-29 08:51 |
And of course, the most important argument that preserving type(x)(repr(x))==x is futile: try it with x=False. (Yes, bools are numbers too.:)
On the other hand, of course, literal_eval treats 'False' completely fine.
|
msg269496 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2016-06-29 14:09 |
Right, that isn't the invariant. Eval is the normal invariant, but not all classes *can* meet it, in which case if they can provide a repr that *can* be turned back into the value losslessly somehow, that's better than not doing so at all.
Still, changing the repr would be the best way to meet the desired invariant, if we're willing to do that. This could be the first stdlib case of a non-string having a useful __str__ if we make the __str__ still return what the current __repr__ does.
|
msg269500 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2016-06-29 14:21 |
...but hopefully not the last. People are playing (with BDFL's blessing) with the idea of types having just (qual)name as str.
By "first stdlib case" you mean "first builtin case", right? fractions.Fraction and decimal.Decimal are in stdlib. :-)
Yes, not all classes can (nor should) support the strong "literal_eval being left-inverse of repr" invariant, but IMO builtin value-like (having a meaningful ==/hash infrastructure separate from identity) classes should. Numbers are surely in that camp.
|
msg269505 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2016-06-29 14:37 |
Ah, I haven't used Fractions and Decimal much, so I hadn't noticed. Those postdate complex, I think, but do follow the model Mark is suggesting. Seems like it would be reasonble to make complex do the same...the concern of course is backward compatibilty.
|
msg273421 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2016-08-23 08:21 |
Unfortunately, as http://bugs.python.org/issue23229#msg233965 shows, Guido is against changing complex.__repr__. Is there any chance someone could show this discussion to him, to show how it would help and try to change his mind?
|
msg273438 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-08-23 12:41 |
> Unfortunately, as http://bugs.python.org/issue23229#msg233965 shows, Guido is against changing complex.__repr__.
Good catch! I think that means we should close this issue. The current behaviour isn't actually wrong; it's just a compromise between lots of different concerns.
|
msg273473 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2016-08-23 16:00 |
Since I'm so happy with Fraction being fixed, I'll agree here. :-)
|
|
Date |
User |
Action |
Args |
2022-04-11 14:58:32 | admin | set | github: 71550 |
2016-08-23 16:00:45 | veky | set | messages:
+ msg273473 |
2016-08-23 12:41:13 | mark.dickinson | set | status: open -> closed resolution: wont fix messages:
+ msg273438
|
2016-08-23 08:21:50 | veky | set | messages:
+ msg273421 |
2016-07-03 01:16:11 | ppperry | set | title: Complex numbers with negative zero imaginary parts do not roundtrip properly -> Complex numbers with negative zero parts do not roundtrip properly |
2016-06-29 16:16:46 | ppperry | set | title: Complex with negative zero imaginary part -> Complex numbers with negative zero imaginary parts do not roundtrip properly |
2016-06-29 14:37:58 | r.david.murray | set | messages:
+ msg269505 |
2016-06-29 14:21:39 | veky | set | messages:
+ msg269500 |
2016-06-29 14:09:01 | r.david.murray | set | messages:
+ msg269496 |
2016-06-29 08:51:47 | veky | set | messages:
+ msg269468 |
2016-06-26 01:05:26 | veky | set | messages:
+ msg269270 |
2016-06-25 15:17:51 | mark.dickinson | set | messages:
+ msg269242 |
2016-06-25 12:22:50 | veky | set | messages:
+ msg269233 |
2016-06-24 15:55:24 | mark.dickinson | set | messages:
+ msg269189 |
2016-06-24 14:39:34 | r.david.murray | set | status: closed -> open resolution: rejected -> (no value) messages:
+ msg269181
stage: resolved -> |
2016-06-23 21:32:06 | veky | set | messages:
+ msg269144 |
2016-06-23 14:35:27 | r.david.murray | set | status: open -> closed
nosy:
+ r.david.murray messages:
+ msg269113
resolution: rejected stage: resolved |
2016-06-21 19:38:12 | mark.dickinson | set | messages:
+ msg269015 |
2016-06-21 19:27:37 | mark.dickinson | set | nosy:
+ mark.dickinson messages:
+ msg269014
|
2016-06-21 19:02:08 | veky | create | |