The (non-)return of the Python print statement
Benefits for LWN subscribers The primary benefit from subscribing to LWN is helping to keep us publishing, but, beyond that, subscribers get immediate access to all site content and access to a number of extra site features. Please sign up today! |
In what may have seemed like an April Fool's
Day joke to some, Python creator Guido van Rossum recently floated
the idea of bringing back the print statement—several months after
Python 2, which had such a statement, reached its end of life. In fact, Van
Rossum acknowledged that readers of his message to the python-ideas mailing
list might be checking the date: "No, it's not April 1st.
" He
was serious about the idea—at least if others were interested in having the
feature—but he withdrew it fairly quickly when it became clear that there
were few takers. The main reason he brought it up is interesting, though:
the new parser for CPython makes it
easy to bring back print from Python 2 (and before).
Prior to Python 3, the print statement was the usual way to print output to the screen:
>>> print '1 + 2 = ', 1+2 1 + 2 = 3But Python 3 changed print from a statement to the print() function. Of the changes for Python 3, switching to print() was perhaps one of the easiest, but it still led to a fair number of complaints. It was rather straightforward for Python 2 code to adopt the new behavior using:
from __future__ import print_functionBut the change did break a lot of working code, so perhaps it makes sense to bring back the print statement, Van Rossum said.
The new parser is based on a parsing
expression grammar (PEG) and it was a fairly simple matter to make the
change: "One thing that the PEG parser makes possible in about 20
lines of code is something not entirely different from the old print
statement.
" He has a prototype working, but it enables far more
than just print statements:
>>> len "abc" 3Or any method:
>>> import sys >>> sys.getrefcount "abc" 24Really, *any* method:
>>> class C: ... def foo(self, arg): print arg ... >>> C().foo 2+2 4
He noted that there are some downsides too, including a "bare" print statement being interpreted as the print() function and not a call to it. Potentially more problematic is the behavior when the first argument to the print statement uses parentheses.
>>> print (1, 2, 3) 1 2 3[...]
>>> print (2+2), 42 4 (None, 42)
Currently a bunch of effort is made in the parser to
recognize code that is trying to use the print statement, so that it
results in a SyntaxError that suggests adding parentheses
("Did you mean print('hello world')
"). That
code could be removed if print was resurrected. Van Rossum said
that it was not an "all or nothing" proposal, it could be dialed back
somewhat by restricting what kinds of function calls it would work for or
restricting it only to "print". He also noted that he would
withdraw the idea "if the response is a resounding 'boo, hiss'
".
It may not have been resounding, but the response was definitely mostly of
the "boo, hiss" variety (including some that used that phrase directly, of
course). Ethan Furman said
that while too many parentheses made code hard to read for him, too few is
also problematic, so he was not in favor of any change. Naomi Ceder had
mixed feelings; she has struggled to switch to the
print() function over the last five years (after 15 years of
print without parentheses). "As someone who teaches Python
and groans at explaining exceptions, I'm -0 on print without parens and -1
on other calls without parens.
"
Gregory P. Smith agreed
with Ceder,
but took it further ("-1 overall for me...
"), even though
Smith liked the print statement for Python 2 and earlier.
Beyond just print, though, he is concerned that calling functions
without requiring parentheses will just lead to "a whole new world of
typos and misunderstandings
". Other languages allow that kind of
thing, but Python is not those languages.
"I love that the new parser allows us to even explore these possibilities.
We should be very cautious about what syntax changes we actually adopt.
"
Overall, Smith's sentiment seemed popular; there were some who viewed parts of the idea favorably, but the full-blown proposal, including making any kind of call without parentheses, was not well-liked. For his part, Van Rossum said there was an element of "because we can" to the idea; he was pleasantly surprised at how easy it was to make it work with the new parser. He described why the PEG parser made things so much easier in his initial message:
But Van Rossum said that he would "happily withdraw
" the idea
since it did not seem to be gaining any real traction. It seems likely
that the idea came out of the blue for many—there were multiple good
reasons to switch to a print() function as part of the
Python 3 transition, after all. But the proposal does serve another purpose: it
allows the CPython core developers to see the scope of the types of changes
the PEG parser is bringing to the table. That may well open up some
interesting features moving forward.
Index entries for this article | |
---|---|
Python | Enhancements |
(Log in to post comments)
The (non-)return of the Python print statement
Posted Jul 1, 2020 22:18 UTC (Wed) by benhoyt (subscriber, #138463) [Link]
The (non-)return of the Python print statement
Posted Jul 1, 2020 22:57 UTC (Wed) by jafd (subscriber, #129642) [Link]
If the proposal got accepted, though, I'm wondering if there wouldn't be an ambiguity if a function call was without arguments: is this a reference to the function itself or to its result? Or should we specify &foo for the former, like, again, Perl?
The (non-)return of the Python print statement
Posted Jul 2, 2020 13:57 UTC (Thu) by smitty_one_each (subscriber, #28989) [Link]
The (non-)return of the Python print statement
Posted Jul 3, 2020 1:34 UTC (Fri) by joey (guest, #328) [Link]
The (non-)return of the Python print statement
Posted Jul 3, 2020 3:45 UTC (Fri) by ibukanov (subscriber, #3942) [Link]
The (non-)return of the Python print statement
Posted Jul 3, 2020 10:04 UTC (Fri) by marcH (subscriber, #57642) [Link]
Exactly https://en.wikipedia.org/wiki/There%27s_more_than_one_way...
The (non-)return of the Python print statement
Posted Jul 1, 2020 23:34 UTC (Wed) by kjp (guest, #39639) [Link]
There is a whole lot of venting I could post in response to this right now, but I'm done. I'm just done.
The (non-)return of the Python print statement
Posted Jul 2, 2020 9:02 UTC (Thu) by dw (guest, #12017) [Link]
The (non-)return of the Python print statement
Posted Jul 3, 2020 5:52 UTC (Fri) by NYKevin (subscriber, #129325) [Link]
To be fair, GvR means "because we can now." In earlier Python 3.x, this was not possible. See for example this code, which is trying to decide whether or not the syntax error we are about to raise was caused by a 2.x-style print statement.
TL;DR: It's processing the code as a raw string, by hand. No AST, no tokenizer, just raw Unicode. It's mostly equivalent to grep -E '^[[:space:]]*print '. It should be entirely unsurprising that you can't "simply" convert this custom syntax error into a valid parse.
The (non-)return of the Python print statement
Posted Jul 2, 2020 0:02 UTC (Thu) by roc (subscriber, #30627) [Link]
The (non-)return of the Python print statement
Posted Jul 2, 2020 0:48 UTC (Thu) by maney (subscriber, #12630) [Link]
Or maybe my fingers are just lazy - they keep trying to leave the parens off of dir, too. :-)
The (non-)return of the Python print statement
Posted Jul 3, 2020 14:23 UTC (Fri) by raoni (guest, #137137) [Link]
The (non-)return of the Python print statement
Posted Jul 2, 2020 1:03 UTC (Thu) by kokada (guest, #92849) [Link]
One case that I think having function without parenthesis helps is when you're calling multiple functions, something like:
print fn1(fn2(foo))
But in this case, I really prefer thread macros instead:
(-> foo fn2 fn1 print)
I would love if Python introduced something like above instead.
The (non-)return of the Python print statement
Posted Jul 2, 2020 9:25 UTC (Thu) by ragnar (guest, #139237) [Link]
You could do something like this:def apply(first_arg, *args): res = first_arg for item in args: res = item(res) return res def partial(fn, *args): def _inner(*inner_args): return fn(*(args + inner_args)) return _inner apply('foo', len, partial(operator.mul, 7), print)
The (non-)return of the Python print statement
Posted Jul 3, 2020 16:22 UTC (Fri) by xi0n (subscriber, #138144) [Link]
The (non-)return of the Python print statement
Posted Jul 9, 2020 1:13 UTC (Thu) by kokada (guest, #92849) [Link]
The (non-)return of the Python print statement
Posted Jul 5, 2020 19:58 UTC (Sun) by NAR (subscriber, #1313) [Link]
Elixir came to my mind as well when I read this article. It's really confusing when parenthesis are omitted, but I think that's what makes some Ecto code look like SQL, e.g. instead of this:
query = from(c in City, select: {c.name, c.population})
one can write
query = from c in City, select: {c.name, c.population}
The (non-)return of the Python print statement
Posted Jul 6, 2020 19:24 UTC (Mon) by niner (subscriber, #26151) [Link]
my &composed = &print ∘ &fn2 ∘ &fn1;
composed(foo);
or directly:
(&print ∘ &fn2 ∘ &fn1)(foo)
Particularily handy in combination with the reduction meta operator [] when you have a list of functions:
my &composed = [∘] @function-list; # i.e. @function-list[0] ∘ @function-list[1] ∘ @function-list[2] ...
composed foo; # because parentheses aren't really needed anyway
The (non-)return of the Python print statement
Posted Jul 2, 2020 1:04 UTC (Thu) by ncm (guest, #165) [Link]
>>> print (2+2) 42
4 42
but no one would ever have wanted that.
The (non-)return of the Python print statement
Posted Jul 2, 2020 2:24 UTC (Thu) by NYKevin (subscriber, #129325) [Link]
The (non-)return of the Python print statement
Posted Jul 2, 2020 10:11 UTC (Thu) by mina86 (guest, #68442) [Link]
The (non-)return of the Python print statement
Posted Jul 2, 2020 11:10 UTC (Thu) by dskoll (subscriber, #1630) [Link]
The (non-)return of the Python print statement
Posted Jul 2, 2020 13:34 UTC (Thu) by jafd (subscriber, #129642) [Link]
To pass an actual subroutine reference somewhere, you need to specify it as \&foo.
The (non-)return of the Python print statement
Posted Jul 2, 2020 13:49 UTC (Thu) by dskoll (subscriber, #1630) [Link]
I know. I posted a link to a funny XKCD cartoon.
The (non-)return of the Python print statement
Posted Jul 2, 2020 13:51 UTC (Thu) by jafd (subscriber, #129642) [Link]
The (non-)return of the Python print statement
Posted Jul 2, 2020 10:55 UTC (Thu) by rschroev (subscriber, #4164) [Link]
Just because you can do something, doesn't mean you should..
The (non-)return of the Python print statement
Posted Jul 2, 2020 13:43 UTC (Thu) by jafd (subscriber, #129642) [Link]
I'd rather have a demonstration of how one could, for example, create a new type of string — say I want to embed SQL which will get validated all over my codebase before my program even runs.
the_sql = sql"SELECT * FROM foobar WHERE (x = :placeholder)"
And if my little prerun hook is not present, the string is being treated as just string.
Or make it HTML, or whatever else code or markup that you'd like to throw over the fence at another system.
But for all gods' sake, let the print statement burn already. You Python people were putting it down for 12 years already, and it saddens me to no end that some people still can't let go of it.
The (non-)return of the Python print statement
Posted Jul 5, 2020 12:58 UTC (Sun) by quotemstr (subscriber, #45331) [Link]
As for Python's PEG parser: I really dislike this trend towards complicated and context-sensitive language grammars. I don't want to have to backtrack across half a megabyte of crap to figure out what a token means. LALR is powerful enough to express anything you might reasonably want in a programming language. For God's sake, let's keep language grammars simple.
[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n...
The (non-)return of the Python print statement
Posted Jul 5, 2020 19:46 UTC (Sun) by NAR (subscriber, #1313) [Link]
The (non-)return of the Python print statement
Posted Jul 5, 2020 19:48 UTC (Sun) by Cyberax (✭ supporter ✭, #52523) [Link]
The (non-)return of the Python print statement
Posted Jul 11, 2020 14:21 UTC (Sat) by nix (subscriber, #2304) [Link]
The (non-)return of the Python print statement
Posted Jul 14, 2020 5:01 UTC (Tue) by jezuch (subscriber, #52988) [Link]
The (non-)return of the Python print statement
Posted Jul 18, 2020 11:17 UTC (Sat) by flussence (subscriber, #85566) [Link]