On Mon, May 31, 2021 at 11:41 PM Steven D'Aprano firstname.lastname@example.org wrote:
It's pretty standard behaviour for Python. Right now, `eval(repr(...))` works unless you have shadowed the name Ellipsis.
>>> err = ValueError('something went wrong') >>> ValueError = list >>> eval(repr(err)) ['s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', ' ', 'w', 'e', 'n', 't', ' ', 'w', 'r', 'o', 'n', 'g']
Yeah, my surprise was kind of a "thinko." I think I was thinking of the eval() separately from the repr(). But nonetheless, the idempotency question still arises, and I believe is reasonable.
Unless we make the ellipsis object `...` callable. But that doesn't help us if the name Ellipsis has been rebound. Then it will call the rebound object.
Let's change the behavior of the Ellipsis object slightly to have either a .__call__() or .__getitem__() method that returns itself
That was exactly what I suggested. The three dots themselves, which CANNOT be bound to any other object, could be callable or indexable. If you define a class Ellipsis to use that name, it makes no difference to `repr(...) == "...[Ellipsis]"` Note that I am NOT proposing `Ellipsis(...)` as the repr for EXACTLY that reason.
Not every builtin needs a mollyguard to protect against misuse.
I'm not likely to rebind `Ellipsis` so that's not really my concern. Rather, I'm interested in the point André Roberge started the thread with. The repr of '...' should be more self-explanatory to beginners. It's basically co-opting the square brackets or parenthesis to mean something that doesn't really have anything to do with calling or indexing in order to have a repr—in tracebacks specifically, but elsewhere also—that reminds users of the connection between `...` and `Ellipsis`.