views:

974

answers:

5

This question was bugging me for quite a while (as evidenced by my previous question): why exactly is print(x) better (which is defined as being more pythonic) than print x?

For those who don't know, the print statement was changed into function in Python 3.0. The formal documentation is in PEP 3105 and motivation is in Guido van Rossum's email.

To those points I would like to make a counterpoint:

  1. There are other operators, such as import which we write as a statement, though their functionality is actually duplicated with a function __import__
  2. To beginners, the operator print does not belong to the general application logic. To them it's the mysterious operator which is a culmination of their program. They expect it to look differently.
  3. All the beginner books which were describing basic Python 2.x are now guaranteed to be broken from the fist example. Certainly, languages sometimes changes, but changes are usually less visible to novices.
  4. It's not immediately obvious to me that a functionality of print can be duplicated on an application level. For example, sometimes I would like to redirect print from a console as a modal OS dialog.
  5. While people say it's hard to rewrite all print statements to a function, they have forced every Python 2.x developer to do exactly that for all their projects. Good, it's not hard with automatic converter.
  6. Everyone who enjoys having an ability to manipulate function print would be just as well-served if print was a statement wrapping function __print__.

So, can we please have a canonical answer to this question on the pages of Stack Overflow?

+6  A: 

The print statement also carries the unusual >> syntax for printing to a specific file. There is no other statement in Python that has this syntax, so it is unusual in that way.

I believe you are right though, most of the problems with the print statement could have been solved by the introduction of a __print__ function.

Greg Hewgill
I'm tempted to accept an answer that agrees with my thoughts most. I wonder if that's impolite to others.
ilya n.
The creteria for acceptance vary much, and often include the number of votes. Thus accepting the highest voted answer usually isn't a bad idea and certainly isn't impolite. :)
Noldorin
Well, I hoped to have a canonical answer to my exact question... but yeah, that could wait.
ilya n.
+5  A: 

I found GvR's "print is the only application-level functionality that has a statement dedicated to it" convincing. Python is a general-purpose language, and shouldn't have a statement for outputting to a stream as an operator or keyword.

Jacob
as my point 4 says, I would be interested in having print which can do more than sys.stdout.write()
ilya n.
I think the combination of write and format strings are in alignment with C's printf/sprintf family which have stood the test of time
Aiden Bell
@ilya, but how would one control exactly how print should be translated. It seems to me that it would be up to the host of the script (the interpreter, etc.) to determine how to handle the output. The host consuming what the script writes to stdout and stderr seems like the best way to implement this.
Jacob
I would think of a print as a more novice-type thing, that is, used by people who don't even have an idea about stdout.
ilya n.
+1  A: 

It is not pythonic because the syntax should be:

stdout.append("Hello World")

or

stdout += "hello world"

Disclaimer: I like Python really.

On a serious note ...

I think that Python's object model and 'Implement it yourself' approach to things like attribute visibility is great. I think that this 'everything is an object' approach to OOP, and even the objects defined as a collection of objects structure is very clear-minded.

What I fear Python will do is become a language that doesn't present it's intentions in a clear way ... and I would hate to see the beauty of the principles get bogged down in over-thinking the already unconventional syntax presentation. Sort of like Lisp, beautiful in it's structure, grim, imho in it's syntax.

Aiden Bell
I'm certain str(stdout) would produce a string which by definition won't be connected with output in any way. Maybe stdout += 'Hello world!' would be closer to what you mean.
ilya n.
@ilya - I think my british dry sense of humour was lost. I will add your suggestion to increase the humour factor :)
Aiden Bell
Why, I think I get it. I do think it *would* be somewhat more pythonic to write like you say.
ilya n.
+23  A: 

Looks to me like yours is a debate, not a question -- are you really going to accept an answer that shows how deeply and badly wrong you were in your assertions?!

On to your debating points:

There are other operators, such as import which we write as a statement, though their functionality is actually duplicated with a function __import__

Absolutely wrong: function __import__ (like every other function -- and operator, for that matter) binds no names in the scope of "caller" (code containing it) -- any "thingie" that binds names in the "caller's scope" must be a statement (just like assignment, def, and call). Your "point" appears to totally miss the extremely deep and crucial distinction that Python draws between statements and expressions -- one may reasonably dislike this distinction, but ignoring it is, most obviously, simply wrong.

Python statements are things the Python compiler must be specifically aware of -- they may alter the binding of names, may alter control flow, and/or may need to be entirely removed from the generated bytecode in certain conditions (the latter applies to assert). print was the only exception to this assertion in Python 2; by removing it from the roster of statements, Python 3 removes an exception, makes the general assertion "just hold", and therefore is a more regular language. Special cases are not special enough to break the rules has long been a Pythonic tenet (do import this at an interactive interpreter's >>> prompt to see "the Zen of Python" displayed), and this change to the language removes a violation of this tenet that had to remain for many years due to an early, erroneous design decision.

To beginners, the operator print does not belong to the general application logic. To them it's the mysterious operator which is a culmination of their program. They expect it to look differently.

Curing beginners of their misconceptions as early as feasible is a very good thing.

All the beginner books which were describing basic Python 2.x are now guaranteed to be broken from the fist example. Certainly, languages sometimes changes, but changes are usually less visible to novices.

Languages rarely change in deep and backwards-incompatible ways (Python does it about once a decade) and few language features are "highly visible to novices", so the total number of observations is small -- yet even within that tiny compass we can easily find counter-examples, where a feature highly visible to beginners was just so badly designed that removing it was well worth the disruption. For example, modern dialects of Basic, such as Microsoft's Visual Basic, don't use explicit user-entered line numbers, a "feature" that was both terrible and highly visible to absolutely everybody since it was mandatory in early dialects of Basic. Modern variants of Lisp (from Scheme onwards) don't use dynamic scoping, a misfeature that was sadly highly visible (usually manifesting as hard-to-understand bugs in their code) to beginners, basically as soon as they started writing functions in Lisp 1.5 (I once was a beginner in that and can testify to how badly it bit me).

It's not immediately obvious to me that a functionality of print can be duplicated on an application level. For example, sometimes I would like to redirect print from a console as a modal OS dialog.

Not sure I follow this "point". Just change sys.stdout to your favorite pseudo-file object and redirect to your heart's contents -- you have the option of monkey patching the built-in function print (which you never had in Python 2), but nobody's twisting your arm and forcing you to do so.

While people say it's hard to rewrite all print statements to a function, they have forced every Python 2.x developer to do exactly that for all their projects. Good, it's not hard with automatic converter.

The 2to3 tool does indeed take care of all such easy surface incompatibilities -- no sweat (and it needs to be run anyway to take care of quite a few more besides print, so people do use it extensively). So, what's your "point" here?

Everyone who enjoys having an ability to manipulate function print would be just as well-served if print was a statement wrapping function print.

Such an arrangement would not, per se, remove an unnecessary keyword (and most especially, an unjustified irregularity, as I explained above: a statement that has no good reason to be a statement because there is absolutely no need for the compiler to be specially aware of it in any way, shape, or form!). It's far from clear to me that having such an underlying function would add any real value, but if you have real use cases you can certainly propose the case in the Python Ideas mailing list -- such an underlying function, if proven to be precious indeed, could be retrofitted to be used by the print statement in Python 2.7 as well as by the print function in Python 3.2.

However, consider a typical case in which one might want to monkey-patch the built-in print: adding keyword arguments to allow fancy tweaks. How would the __print__ function you're apparently proposed ever ge those KW arguments from a __print__ statement? Some funkier syntax yet than the horrors of >> myfile and the trailing comma...?! With print as a function, keyword arguments follow just the perfectly normal and ordinary rules that apply to every function and function call -- bliss!

So, in summary, it's more Pythonic for print to be a function because it removes anomalies, special cases, and any need for weird exceptional syntax -- simplicity, regularity, and uniformity are Python's trademark.

Alex Martelli
As per my original post, I value an answer to the question, especially if this answer also shows how bad my points are. FYI, you have my vote, the only at the moment. Yes, I'm going to accept a post similar to yours.
ilya n.
@ilya, I stand corrected and apologize for inferring otherwise on a basis that was clearly too flimsy and not supportable -- sorry.
Alex Martelli
+2  A: 

Here's the reason I hate the print statement in 2.x.

>>> something()
<something instance at 0xdeadbeef>
>>> print something()
<something instance at 0xdeadbeef>

worthless object has no useful __str__, Fine, I can deal, look at it some more.

>>> dir(something())
['foo', 'bar', 'baz', 'wonderful']
>>> help(something().foo)
"foo(self, callable)"

hmm.. so does that callable take arguments?

>>> something().foo(print)
    something().foo(print)
                        ^
SyntaxError: invalid syntax
>>> something().foo(lambda *args: print(*args))
    something().foo(lambda *args: print(*args))
                                      ^
SyntaxError: invalid syntax

So... I have to either define a function to use

>>> def myPrint(*args): print *args
    def myPrint(*args): print *args
                              ^
SyntaxError: invalid syntax
>>> def myPrint(*args): print args
...
>>> myPrint(1)
(1,)

Shudder, or use sys.stdout.write, which is almost as cludgy, since it has very different behavior from print. It also looks different, which means I'll almost never remember that it exists.

Using print statements in a short, one-off type facility and then improving it to use logging or something better is just inelegant. If print worked like those things, and especially could be used with high order functions, then it would be better than just the thing you use when you don't use real logging or real debuggers.

TokenMacGuy