[Python-ideas] Unambiguous repr for recursive objects
Nick Coghlan
ncoghlan at gmail.com
Sat Dec 26 06:08:18 EST 2015
On 26 December 2015 at 19:28, Serhiy Storchaka <storchaka at gmail.com> wrote:
> The problem is that "[...]", and "{...}", and just "..." are valid Python
> expressions and above representations can be evaluated to different objects.
I believe this is just an oversight from when "..." became usable
outside subscripts in 3.0, but I agree it's a discrepancy worth
addressing.
> I propose to use uniform and unambiguous non-evaluable representation for
> recursive objects. I have two ideas:
>
> 1. "<...>".
>
> Plus: this is as short as "[...]" and "{...}".
>
> Minus: we loss even a little tip about the type of recurred object.
I think that would still be an improvement - the hinting only works
for types with native syntax anyway, while for arbitrary containers
it's already necessary to fall back to a generic notation like
"<...>".
> 2. Use the default implementation, object.__repr__(). E.g. "<list object at
> 0xb7111498>".
Another minor disadvantage is that it's not as easy to write doctests
or simple examples, as the repr isn't predictable (or you have to put
a "..." in as a placeholder for the ID anyway). A larger disadvantage
is that you can't readily spot that it's a recursive reference, since
that's implicit in the ID of the given object.
To make this less abstract, here's a simple example:
>>> a = [1, 2]
>>> b = [a]
>>> a.append(b)
>>> a
[1, 2, [[...]]]
>>> b
[[1, 2, [...]]]
With the first alternative, that becomes:
>>> a
[1, 2, [<...>]]
>>> b
[[1, 2, <...>]]
I think that's actually clearer than the status quo (since the
circular reference is more visually distinct), but it would retain the
current ambiguity if the containers also reference themselves:
>>> a.append(a)
>>> b.append(b)
>>> a
[1, 2, [[...], [...]], [...]]
>>> b
[[1, 2, [...], [...]], [...]]
That scenario is likely rare enough not to worry about - visualising
such data structures sensibly is tough in general, and arguably best
left to use case specific display routines, rather than trying to
handle it with the default container repr.
If the recursive display changed to use object.__repr__ instead, we'd
get something like:
>>> object.__repr__(a)
'<list object at 0x7fc755edd488>'
>>> object.__repr__(b)
'<list object at 0x7fc755eea0c8>'
>>> a
[1, 2, [<list object at 0x7fc755edd488>, <list object at
0x7fc755eea0c8>], <list object at 0x7fc755edd488>]
>>> b
[[1, 2, <list object at 0x7fc755eea0c8>, <list object at
0x7fc755edd488>], <list object at 0x7fc755eea0c8>]
So +1 from me for switching to "<...>" in 3.6+ to make the default
recursive repr for containers an invalid expression again, but only +0
for using the full object.__repr__ - the extra precision in the more
complex case hurts readability in the typical case, without really
improving readability in the complex cases that would be the intended
beneficiaries.
Regards,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
More information about the Python-ideas
mailing list