[Python-ideas] A nice __repr__ for the ast.* classes?

10 views
Skip to first unread message

Haoyi Li

unread,
Apr 30, 2013, 9:12:55 PM4/30/13
to python-ideas
Wouldn't it be nice if this

>>> import ast
>>> print repr(ast.parse("(1 + 1)").body[0].value)
<_ast.BinOp object at 0x0000000001E94B38>

printed something more useful?

>>> print repr(ast.parse("(1 + 1)").body[0].value)
BinOp(left=Num(n=1), op=Add(), right=Num(n=1))

I've been doing some work on macropy, which uses the ast.* classes extensively, and it's annoying that we have to resort to dirty-tricks like monkey-patching the AST classes (for CPython 2.7) or even monkey-patching __builtin__.repr (to get it working on PyPy) just to get 

    eval(repr(my_ast)) == my_ast 

to hold true. And a perfectly good solution already exists in the ast.dump() method, too! (It would also be nice if "==" did a structural comparison on the ast.* classes too, but that's a different issue).

-Haoyi

Guido van Rossum

unread,
Apr 30, 2013, 9:21:12 PM4/30/13
to Haoyi Li, python-ideas
But do you really want it to print the entire parse tree even if it
represents several pages of code?
> _______________________________________________
> Python-ideas mailing list
> Python...@python.org
> http://mail.python.org/mailman/listinfo/python-ideas
>



--
--Guido van Rossum (python.org/~guido)
_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas

Steven D'Aprano

unread,
Apr 30, 2013, 9:33:10 PM4/30/13
to python...@python.org
On 01/05/13 11:21, Guido van Rossum wrote:
> But do you really want it to print the entire parse tree even if it
> represents several pages of code?

Large dicts have the same problem. I can't tell you the number of times I've printed an apparently innocent dict that happened to have builtins in it. I don't think there's any good solution to this. My feeling is that the usefulness of small {dicts | parse trees} having a nice repr outweighs the inconvenience of large ones having a big repr, but I would understand if others had a different opinion.



--
Steven

Haoyi Li

unread,
Apr 30, 2013, 9:35:06 PM4/30/13
to Guido van Rossum, python-ideas
Isn't that the distinction between repr() and str()? That repr() is generally (to a greater extent) meant to return eval()-able code, while str() is just something nice to look at.

I don't think the # of pages it outputs should really matter, if the thing you are printing really is that big. It won't be much bigger than printing big lists or dicts, and we happily let those cause the terminal to scroll for minutes at a time if we accidentally print them. The default behavior (e.g. when you print() it or string-interpolate it) would still give you something short and nice to look at. Presumably when someone called repr() instead of str(), he was hoping for some sort of eval()-able code snippet.

Nick Coghlan

unread,
Apr 30, 2013, 11:51:36 PM4/30/13
to Haoyi Li, python-ideas
On Wed, May 1, 2013 at 11:35 AM, Haoyi Li <haoy...@gmail.com> wrote:
> Isn't that the distinction between repr() and str()? That repr() is
> generally (to a greater extent) meant to return eval()-able code, while
> str() is just something nice to look at.

The stronger distinction is that repr() is ideally never ambiguous
about the corresponding value, while str() might be. For example:

>>> "1"
'1'
>>> 1
1
>>> str("1")
'1'
>>> str(1)
'1'

That desire for an unambiguous repr for each value is why CPython
defaults to using "<TYPE at ADDRESS>"

Having repr support eval is certainly nice when practical, but it's
far from a requirement. Even the desire for a unique repr-per-value
isn't a guarantee, since some types *do* impose a size limit.

> I don't think the # of pages it outputs should really matter, if the thing
> you are printing really is that big. It won't be much bigger than printing
> big lists or dicts, and we happily let those cause the terminal to scroll
> for minutes at a time if we accidentally print them. The default behavior
> (e.g. when you print() it or string-interpolate it) would still give you
> something short and nice to look at. Presumably when someone called repr()
> instead of str(), he was hoping for some sort of eval()-able code snippet.

In this particular case, I'm also inclined to favour the approach of
using ast.dump as the repr for AST nodes. Call it +0.

Adding support for depth limiting and peer node limiting to ast.dump
(with missing nodes replaced with "...") would also be neat.

Cheers,
Nick.

--
Nick Coghlan | ncog...@gmail.com | Brisbane, Australia

anatoly techtonik

unread,
Nov 19, 2013, 12:55:30 PM11/19/13
to Nick Coghlan, python-ideas
On Wed, May 1, 2013 at 6:51 AM, Nick Coghlan <ncog...@gmail.com> wrote:
>
> In this particular case, I'm also inclined to favour the approach of
> using ast.dump as the repr for AST nodes. Call it +0.
>
> Adding support for depth limiting and peer node limiting to ast.dump
> (with missing nodes replaced with "...") would also be neat.

https://bitbucket.org/techtonik/astdump/src/ed73edbdccb5fd9d4255d7ed64f45b6922447ecb/astdump.py?at=default#cl-35
Something like this?
--
anatoly t.
_______________________________________________
Python-ideas mailing list
Python...@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Reply all
Reply to author
Forward
0 new messages