It became a function because it always should have been one. However, since it wasn't always a function, they didn't have the common sense to pick a NEW function name (puts, println, write, writeln, echo, say, show, ...) and politely deprecate the old print syntax. Shortsighted and pointless.
There's a perfectly good migration mechanism via "from __future__". If you gave the print function a weird name that would be another wart that newcomers would have to learn, and Python 3 was all about making a clean break.
This way people will actually switch. Programmers won't change without being forced.
Also, Python 3 was their one chance to break backwards compatibility. And there are so many breaking changes in there that people will have to change their codebase to work with Py3k anyway. Your suggestion just delays breaking compatibility (or actually, causes a later release to break backwards compatibility when it wouldn't have been necessary otherwise) ...unless you're arguing for keeping the old print in indefinitely. Why deprecate it then? And old cruft with "oh, we have that but don't use it" labels attached is definitely confusing. And the label would be ignored by too many "that's-the-way-I've-learned-it-and-it-still-works-so-whats-the-problem" programmers.
This is one of the most trivial changes 2to3 makes; it can be done 100% reliably statically, it's very local and very mechanical, and if you don't get it right you get a syntax error on startup (instead of exceptions at runtime (e.g. unicode strings) or even different behavior (e.g. integer division)). The print statement->function change is just not that big of a problem when updating codebases to py3k. It's very visible (because everyone knows print), but the other changes will take much more work and be much harder to debug, so why get hung up over it?
print as a statement requires a special syntax rule. When people switch that special case goes away. Maybe that does not account for much on the whole, but language designers tend to be irked by such things.
I see that it's irksome, but as someone who works on the Web Platform, which takes backward compat seriously, I tend to view Python 3 as a mistake. I'm still hoping that they make Python5 that's compatible with Python 2.7 programs but otherwise brings in new features. I'm not holding by breath, though.
The saddest thing about Python 3 is that they made a breaking change to do Unicode "right" and still did it wrong. The right way to do Unicode is the way Rust does it: UTF-8 in memory and no (safe) API to introduce UTF-8 invalidity.
UTF-32 is wrong, bwcause it's wasteful and still doesn't accomplish what people naively expect due to grapheme clusters potentially taking more than one UTF-32 code unit.
Python is UTF-8 by default and only upgrades to UTF-16 / 32 when it would make sense to do so given the characters in the string.
> UTF-32 is wrong, [because] it's wasteful and still doesn't accomplish what people naively expect due to grapheme clusters potentially taking more than one UTF-32 code unit.
Out of curiosity, is there a correct way to encode unicode that doesn't involve this level of surprise? I thought that this was still an unsolved problem at this point.
You get people to accept the truth that characters have a variable length in bytes.
Then you offer a data structure that lets you perform O(1) or O(logn) operations on sequences of single-character strings.
If it's read-only you could make it just be an index, blah blah the details don't matter a lot, the point is you can make something that's both correct to grapheme clusters and probably more space-efficient than UTF-32 despite the extra data.
And then the encoding inside the character strings isn't particularly important, but might as well use UTF-8.
-
Either that or make yourself a hilariously inefficient format based on:
UAX15-D3. Stream-Safe Text Format: A Unicode string is said to be in Stream-Safe Text Format if it would not contain any sequences of non-starters longer than 30 characters in length when normalized to NFKD.
You could argue the opposite too. If print wasn't changed, a Python tutorial from 10 years ago would have a better chance of working on a modern Python installation.
Err, what? Maybe you mean that an arbitrary distinction between statements and expressions makes the language trickier to learn than it otherwise might be. But once you have that distinction, print being a function vs a statement isn't trickier one way or the other.
Print fits much better with python's functions than its statements. I think it is notably tricker if the most common piece of code you pass arguments to has no parentheses, but everything else does.
Well, they have to balance (dis)pleasing both the old users and the new users. Not everyone will be happy, even those that may benefit later on have no way of voicing opinion based on the satisfaction that is yet to come.
On the human side, people do not like to stare at glaring mistakes all the time, if they can do something about it -- having weighed the cost associated with the change.
In 20 years if python is still a thing, it likely will not be because it was designed right from the get go. It will be because it changed enough to stay relevant despite the fact that some changes may have left incompatibilities in their wake. Users have to live with that.
And the great thing about Python 2.7 is it supports both syntaxes: I can, and often do, from __future__ import print_function, but I don't have to; hell, if Python 3 just defaulted that on but let you turn it off for modules on a different import path, that would have been much more intelligent than what they did :/.
> This way people will actually switch. Programmers won't change without being forced.
Nobody likes being forced though. I think that attitude, which is condescending by its nature, is what has been turning people away from Python, in the wake of the version 3 changes.
So, given the incredibly low rate of Python 3 adoption, how well did that "forced" change work out for them? Python 3 deserves its fate, and apologists like you aren't going to change that.
Thanks for the name-calling. Unfortunately, it is you who is out of touch with reality: the switch to Python 3 is happening. Python 3 isn't going away, Python 2 is.
All important Linux distributions ship Python 3, including typical "server distributions", even for old stable versions (like Centos 6, Debian Wheezy). They also ship most Python library packages for both versions.
Most desktop distributions have already switched their default/preferred version (e.g. Arch) or are in the process of it (e.g. Fedora[2], Ubuntu[3]).
And in four years (2020), Python 2 will be unsupported.
Python 3 is the obvious choice for new Python projects today. And maintaining and deploying legacy codebases will become more and more annoying as support (bugfixes, packaging) for the libraries they use goes away.
I miss print as a statement. Especially when I try to debug fast in dummy scripts, and when debugging in REPL (bpython, ipython). I always forget it's a function, and then I have to move the cursor before the printed symbol, type the left parenthesis, move after the symbol, then the right one. It's kind of annoying.
I also miss it. Those parens are a bit annoying to type when doing print debugging. I really appreciate the fact that it makes a lot more sense for it to be a function, however. In time, I'm sure we'll all get used to it.
I don't. It's a habit change so sure once in a while I still forget the parens, but the function form is way more readable when doing anything beyond a bare print[0] — not to mention it can plain do more useful stuff — and I can now put a print function in a lambda instead of needing bullshit like
You mention print in lambda, and it's also in the article. I don't think that's good enough reason for killing the usability of print statement in repl.
I'd consider it quite a weird piece of code if I'd see print in lambda, or passed to something from functools. If "sys.stdout.write" would be there instead of the "print", I'd see it equally weird. Both is (probably unnecessary) giving away the simplicity of Python.
I debug in REPL quite a lot and I don't do functional magic with print at all (at the moment). That's dragging me away from Python 3. Other people might have it different.
It seems silly that typing a single extra character at the end of the line (noting that the left parenthesis was previously a space) is "dragging you away from python". It is also worth noting that the IPython repl will close parentheses for you, so you actually don't have to type any more characters at all!
>I don't think that's good enough reason for killing the usability of print statement in repl.
I really don't think the difference between
print(some_var)
and
print some_var
constitutes "killing usability".
> I'd consider it quite a weird piece of code if I'd see print in lambda
Granted, I don't do much Python these days (I have become enamored with more strongly-typed langs lately), but my impression is that lambdas are uncommon in python, instead preferring relatively-inexpensive toplevel function defs instead.
> I debug in REPL quite a lot and I don't do functional magic with print at all (at the moment)
Consider a case where I'm debugging why my function foo(x) is failing for at least one of [42, 333, -57, 0, None, 33], but I don't know which one. It's not unheard of to do some step-by-step binary-search stuff like this:
>> [print(foo(x)) for x in test_cases[0:3]]
# repl doesn't blow up
>> [print(foo(x)) for x in test_cases[3:]]
# repl blows up as expected
>> [print(foo(x)) for x in test_cases[4:]]
# repl doesn't blow up, so now I know that foo(0) has a bug
Now, you might look at this and point out that I don't actually need to print(foo(x)) at all, that the REPL will display the resulting arrays anyways. And you're right! So even here, the difference between "print(x)" and "print x" doesn't "kill usability", since it's a moot point either way.
I think in day-to-day use, even at a REPL, it's a "six of one, half-dozen of another" scenario with no major wins either way. In teaching Python, it's a win because it's more consistent -- you don't have to teach people "this is how it looks to call a function -- except print, it's not really a real function, it's special, so make sure you remember this one exception." And in building Python, it means one fewer special case to maintain for the interpreter and language.
Having print() as a function was something that helped convince me to teach Python 3, as opposed to 2.x. Don't get me wrong, in Ruby, I'm completely lax in using parentheses in function calls. But when explaining syntax to newbies, about how regular it is, and how it's easy to determine what's a function and what's not by use of parentheses...I want as few as exceptions as possible...and print() is something that beginners especially use a lot.
"Oh no!! We have to write one extra character to print something!" It's almost as bad as if someone forced you to put an unnecessary colon at the end of every single scope-starting line...
I was at europython 2006 when Guido announced that the print statement was getting axed. It was a bit of a shock to me. I think everyone in the audience was altogether not quite sure where/why python 3000 was coming and so willing to patiently listen to what the master had to say about all of it.
Guido's reasoning seemed to be that since a bunch of junior devs at google couldn't refactor their print statements into logging statements the print statement had to go.
I don't seem to have this issue: for me the print statement is 99% used as a debugging tool. When I'm debugging I pepper my code with print statements until it tells me what is going wrong. So two extra parens every time i do this just seems unreasonable to me. Excuse my whining, but there it is.
I was also at europython in 2007 when Guido once again went over the changes being wrought by python 3. This time when he got to the print statement I let out a loud "BOO!" Guido was somewhat surprised and remarked: "well no-one said anything about this when I announced it at last year's europython!"
36 comments
[ 3.7 ms ] story [ 85.5 ms ] threadThis way people will actually switch. Programmers won't change without being forced.
Also, Python 3 was their one chance to break backwards compatibility. And there are so many breaking changes in there that people will have to change their codebase to work with Py3k anyway. Your suggestion just delays breaking compatibility (or actually, causes a later release to break backwards compatibility when it wouldn't have been necessary otherwise) ...unless you're arguing for keeping the old print in indefinitely. Why deprecate it then? And old cruft with "oh, we have that but don't use it" labels attached is definitely confusing. And the label would be ignored by too many "that's-the-way-I've-learned-it-and-it-still-works-so-whats-the-problem" programmers.
This is one of the most trivial changes 2to3 makes; it can be done 100% reliably statically, it's very local and very mechanical, and if you don't get it right you get a syntax error on startup (instead of exceptions at runtime (e.g. unicode strings) or even different behavior (e.g. integer division)). The print statement->function change is just not that big of a problem when updating codebases to py3k. It's very visible (because everyone knows print), but the other changes will take much more work and be much harder to debug, so why get hung up over it?
Is that important?
The saddest thing about Python 3 is that they made a breaking change to do Unicode "right" and still did it wrong. The right way to do Unicode is the way Rust does it: UTF-8 in memory and no (safe) API to introduce UTF-8 invalidity.
UTF-32 is wrong, bwcause it's wasteful and still doesn't accomplish what people naively expect due to grapheme clusters potentially taking more than one UTF-32 code unit.
> UTF-32 is wrong, [because] it's wasteful and still doesn't accomplish what people naively expect due to grapheme clusters potentially taking more than one UTF-32 code unit.
Out of curiosity, is there a correct way to encode unicode that doesn't involve this level of surprise? I thought that this was still an unsolved problem at this point.
Then you offer a data structure that lets you perform O(1) or O(logn) operations on sequences of single-character strings.
If it's read-only you could make it just be an index, blah blah the details don't matter a lot, the point is you can make something that's both correct to grapheme clusters and probably more space-efficient than UTF-32 despite the extra data.
And then the encoding inside the character strings isn't particularly important, but might as well use UTF-8.
-
Either that or make yourself a hilariously inefficient format based on:
UAX15-D3. Stream-Safe Text Format: A Unicode string is said to be in Stream-Safe Text Format if it would not contain any sequences of non-starters longer than 30 characters in length when normalized to NFKD.
Who's with me on 128-byte characters.
On the human side, people do not like to stare at glaring mistakes all the time, if they can do something about it -- having weighed the cost associated with the change.
In 20 years if python is still a thing, it likely will not be because it was designed right from the get go. It will be because it changed enough to stay relevant despite the fact that some changes may have left incompatibilities in their wake. Users have to live with that.
Or they could stay on Python 2.7 forever.
Nobody likes being forced though. I think that attitude, which is condescending by its nature, is what has been turning people away from Python, in the wake of the version 3 changes.
All important libraries support it by now.[1]
[1] https://python3wos.appspot.com/
All important Linux distributions ship Python 3, including typical "server distributions", even for old stable versions (like Centos 6, Debian Wheezy). They also ship most Python library packages for both versions.
Most desktop distributions have already switched their default/preferred version (e.g. Arch) or are in the process of it (e.g. Fedora[2], Ubuntu[3]).
[2] https://fedoraproject.org/wiki/Changes/Python_3_as_Default
[3] https://wiki.ubuntu.com/Python/3
The first libraries are beginning to drop Python support (e.g. pyKDE[5]).
[4] https://blogs.kde.org/2014/08/10/pykde5-status
New Python3-only libraries are popping up (at least according to the metadata on PyPi)[6].
[5] https://stackoverflow.com/questions/4948600
And in four years (2020), Python 2 will be unsupported.
Python 3 is the obvious choice for new Python projects today. And maintaining and deploying legacy codebases will become more and more annoying as support (bugfixes, packaging) for the libraries they use goes away.
So what the hell are you talking about?
I don't. It's a habit change so sure once in a while I still forget the parens, but the function form is way more readable when doing anything beyond a bare print[0] — not to mention it can plain do more useful stuff — and I can now put a print function in a lambda instead of needing bullshit like
[0] no magical easy to miss terminal comma or sigil soup for non-stdout printing, clear and readable keyword parameters insteadI'd consider it quite a weird piece of code if I'd see print in lambda, or passed to something from functools. If "sys.stdout.write" would be there instead of the "print", I'd see it equally weird. Both is (probably unnecessary) giving away the simplicity of Python.
I debug in REPL quite a lot and I don't do functional magic with print at all (at the moment). That's dragging me away from Python 3. Other people might have it different.
I really don't think the difference between
and constitutes "killing usability".> I'd consider it quite a weird piece of code if I'd see print in lambda
Granted, I don't do much Python these days (I have become enamored with more strongly-typed langs lately), but my impression is that lambdas are uncommon in python, instead preferring relatively-inexpensive toplevel function defs instead.
> I debug in REPL quite a lot and I don't do functional magic with print at all (at the moment)
Consider a case where I'm debugging why my function foo(x) is failing for at least one of [42, 333, -57, 0, None, 33], but I don't know which one. It's not unheard of to do some step-by-step binary-search stuff like this:
Now, you might look at this and point out that I don't actually need to print(foo(x)) at all, that the REPL will display the resulting arrays anyways. And you're right! So even here, the difference between "print(x)" and "print x" doesn't "kill usability", since it's a moot point either way.I think in day-to-day use, even at a REPL, it's a "six of one, half-dozen of another" scenario with no major wins either way. In teaching Python, it's a win because it's more consistent -- you don't have to teach people "this is how it looks to call a function -- except print, it's not really a real function, it's special, so make sure you remember this one exception." And in building Python, it means one fewer special case to maintain for the interpreter and language.
Guido's reasoning seemed to be that since a bunch of junior devs at google couldn't refactor their print statements into logging statements the print statement had to go.
I don't seem to have this issue: for me the print statement is 99% used as a debugging tool. When I'm debugging I pepper my code with print statements until it tells me what is going wrong. So two extra parens every time i do this just seems unreasonable to me. Excuse my whining, but there it is.
I was also at europython in 2007 when Guido once again went over the changes being wrought by python 3. This time when he got to the print statement I let out a loud "BOO!" Guido was somewhat surprised and remarked: "well no-one said anything about this when I announced it at last year's europython!"
Doh.