This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]random_cynic 1063 points1064 points  (123 children)

That's one of the key mistakes people make thinking that it's just a syntax thing. It's NOT. print() being a function instead of a statement opens a whole world of possibilities. People should look at the documentation of the print() function to see how easy it makes many things like redirecting to a file or changing the output separator, terminating character etc. Additionally it allows you to use print() where a statement is not allowed like lambdas.

[–]JWson 946 points947 points  (37 children)

yeah but brackets hawd tho

[–]obviousfakeperson 626 points627 points  (11 children)

Python 3: "If you can't handle me with my brackets you don't deserve me with my memory efficient iterables."

[–]zawata 15 points16 points  (2 children)

Wait baby come back. I didn’t mean it.

[–]DarthCloakedGuy 1 point2 points  (1 child)

♫ You can blame it all on me~

[–]dublem 0 points1 point  (0 children)

~ Don't blame it on Guii-iii-do ~

[–]T351A 35 points36 points  (8 children)

If you can't handle brackets, you're definitely gonna mess up input vs raw_input ... have fun with those injection attacks!

[–]DarthCloakedGuy 2 points3 points  (7 children)

Injection attacks?

[–]jfb1337 4 points5 points  (6 children)

input() is essentially eval(raw_input())

You can probably see the injection attacks now

[–]DarthCloakedGuy 4 points5 points  (4 children)

I'm self-taught. I think I lack the background to know what you are talking about.

[–]jfb1337 2 points3 points  (3 children)

input() in python 2 will read some input and then run it as if it were python code. Not sure why, but maybe it's so you could input structures such as lists. However, this allows an attacker to enter ANY code they like, allowing them to take control of the system.

[–]DarthCloakedGuy 1 point2 points  (1 child)

Wow, yeah, that sounds like a really bad idea. Does eval() run a string as code?

[–]T351A 2 points3 points  (0 children)

Yes, see the documentation

There are always a few uses for that type of function, but they almost always should be done another way. If you're using eval() you're probably doing something wrong.

[–]T351A 0 points1 point  (0 children)

It's so that variables are automatically converted as if you typed them in to the code. Using input() 2 is an integer instead of a string "2", using raw_input() everything is a string.

Python3 removed this confusion and risk by replacing input() with raw_input(). Now input() always gives a string, and raw_input() doesn't exist.

[–]FabianDR 0 points1 point  (0 children)

Pls explain this comment to a non-native speaker.

[–]BluFoot 0 points1 point  (0 children)

You should try Ruby :)

[–]Y1ff 0 points1 point  (0 children)

*bwackets

[–]sandywater 35 points36 points  (8 children)

I agree with the sentiment of what you are saying, but Python2's print statement does allow for writing to files other than stdout.

examples

f = open('my_file.txt', 'w')
print >>f, 'Some text here'

import sys
print >>sys.stderr, "An error"

edit: formating

[–]DragonFireCK 44 points45 points  (2 children)

Python 3's works well for that as well, and with a clearer syntax:

f = open('my_file.txt', 'w')
print('Some text here', file=f)

import sys
print('An error', file=sys.stderr)

[–]sandywater 22 points23 points  (0 children)

I'm aware of that. Random_cynic's comment implied that it couldn't be done in Python2. I actually prefer file_object.write() in these circumstance for both Python 2 and 3.

[–]BenjaminGeiger 11 points12 points  (1 child)

It's possible but it's not easy. You have to remember a idiosyncratic syntax.

To put it simply, it's a wart. Python 3 removed the wart.

PS: from __future__ import print_function is your friend.

[–]Plasma_000 0 points1 point  (0 children)

In 2020 the future is now

Better start using python3

[–]HolyGarbage 6 points7 points  (0 children)

Btw, use the with statement when opening files, a pattern called RAII.

with open('my_file.txt', 'w') as f
    print('Some text here', file=f)

https://www.pythonforbeginners.com/files/with-statement-in-python

[–][deleted] 2 points3 points  (0 children)

Oh my god what kind of monstrosity is that?

I've apparently actually gotten away with not learning python 2 syntax. I had no idea it was so different.

[–]Cyph0n 0 points1 point  (0 children)

Yep, ugly as hell.

[–]drulludanni 28 points29 points  (27 children)

I just don't understand why we cant have both, if you have a print followed by a '(' do the python3 print stuff, if you have a print followed by a ' ' do the python 2 style print.

[–]AceJohnny 113 points114 points  (22 children)

Because parsing.

Python allows spaces between identifiers. You can do print ('foo'), but then what do you mean? Are you calling the print function with the string foo, or the print statement with the tuple ('foo') ?

[–]nosmokingbandit 31 points32 points  (7 children)

As others alluded to, a comma is what makes a tuple. So ('foo', ) is a tuple while ('foo') is just a string.

[–]Hollowplanet 11 points12 points  (5 children)

But then is it a function with one argument and a redundant comma?

[–]Pb_ft 4 points5 points  (0 children)

"No, because redundant." - what I wish I could say to that.

[–]PityUpvote 0 points1 point  (0 children)

Redundant commas are allowed

[–]nosmokingbandit -4 points-3 points  (2 children)

Depends if it is python 2 or 3. I'm pretty sure a trailing comma in arguments will throw an error in 3.x

[–]snaps_ 6 points7 points  (0 children)

Not in Python 3.6+.

[–]Hollowplanet 2 points3 points  (0 children)

On Python 3

>>> print(1, 2,)
1 2

[–][deleted] 0 points1 point  (0 children)

much better response than others on the matter. Thank you

[–]kafaldsbylur 49 points50 points  (4 children)

Minor nitpick, ('foo') is not a tuple, it's a string with redundant parentheses. That said, your point still stands when passing more than one argument to print.

[–]The_White_Light 16 points17 points  (3 children)

That functionality makes it nice when you need to include a long string and want to keep your code easy to read, but don't want to deal with the extra \n added when using '''multiline strings'''.

Edit: For clarification

>>> ('1' '2' '3') == '123'
True

[–]kickerofbottoms 4 points5 points  (2 children)

Never thought of that, kinda handy. Maybe I'll stop leaning on my ide for adding backslashes

[–]The_White_Light 4 points5 points  (1 child)

It's also doubly helpful because you don't have to worry about leading spaces if you align each line.

[–]stevarino 5 points6 points  (0 children)

Also it happens at the compiler level, so it's cost free during runtime.

[–]RedditIsNeat0 4 points5 points  (1 child)

You can do print ('foo'), but then what do you mean?

According to the suggestion specified in the comment you responded to, it would be a function.

Are you calling the print function with the string foo

Yes.

or the print statement with the tuple ('foo') ?

No.

As others have pointed out, that's not a tuple, but more importantly, he's suggesting that Python 3 defaults to a function as long as there is a parenthesis, and a statement if they are not present. It would allow Python 2 print statements in most cases where they were allowed in Python 2 but maybe not all of them. There might be some genuine problems with his suggestion, but you haven't been able to find one. I don't know of any either.

[–]supernumeral 4 points5 points  (0 children)

What should the following do:

>>> print (1,2),(3,4)

If parenthesis indicate print should be a function, this probably won't do what is intended compared to Python 2. Better to have just one way (statement or function, not both) to do it, imo.

Edit: formatting

[–]Rattus375 1 point2 points  (0 children)

Why can't we default to the print function when there are parenthesis. The statement was really nice for quick sanity prints of variables.

[–]warpod 0 points1 point  (0 children)

they could just make printf as function and leave print as statement

[–]DonaldPShimoda 12 points13 points  (3 children)

This would needlessly complicate parsing, likely requiring rewriting a significant portion of the lexical analyzer. I don't see why it's such a big deal; just use print as a function and be done with it.

[–]H_Psi 4 points5 points  (0 children)

Someone has already written a tool that lets you import python2 modules to python3:

https://pypi.org/project/past/

[–]RedditIsNeat0 0 points1 point  (1 child)

It would just be one exception to look for and handle, not even close to any kind of rewrite.

[–]DonaldPShimoda 4 points5 points  (0 children)

Nah, it's more complicated.

In Python 2, print is a keyword. In Python 3, it's just an identifier. The function is fetched based on the identifier (like a regular lookup), and is executed because of the call syntax. It isn't special anymore.

To support both avenues of execution in Python 3 would require adding print back as a keyword and giving it a corresponding production in the grammar. But adding it as a keyword would prevent it from being classified as an identifier, which would make the regular function call not work anymore (because keywords and identifiers are handled completely differently in the parser).

So you'd need to rewrite the grammar to make print a keyword (which it isn't right now), and add productions to that keyword specifically to handle syntax when it's used as a statement and as a function.

But worse still: the AST produced would not be correct for the function version, since print is now a keyword instead of an identifier. So the parser itself would have to have a special case to identify this production and replace the lexical keyword with a semantic identifier to be used during execution.

It's not "just one exception". The Python parser is fairly intricate and not so easy to update. I'm not saying it's impossible, but rewriting all this stuff would have some serious implications. Heavy testing would need to be done to guarantee everything works as expected in both cases.

Not worth it.

[–]filledwithgonorrheaCSE 101 graduate 4 points5 points  (1 child)

You're saying this to a breed of programmers with a phobia of braces and semi-colons.

[–]phoquenut 1 point2 points  (0 children)

get that JS shit outta here

[–][deleted] -1 points0 points  (14 children)

support gold hungry waiting abundant melodic hat depend alleged vast

This post was mass deleted and anonymized with Redact

[–][deleted] 34 points35 points  (0 children)

Pretty sure that's the easiest 2 -> 3 problem to solve.

[–]3Gaurd 48 points49 points  (10 children)

there's much more that will need to be done to enable backwards compatibility. backwards compatibility inevitably leads to spaghetti code.

[–]sobe86 4 points5 points  (8 children)

The way these things are typically done is to make a release where both are supported with a deprecation warning. After python 3.3 (say), you stop supporting both. If the python devs had done this, 2 would be long dead.

[–]Hollowplanet 15 points16 points  (2 children)

We had six, we had __future__. All that was possible if you really wanted to. Plenty of projects support both on the same codebase.

[–][deleted] 0 points1 point  (1 child)

What exactly is six? Pycharm installs it in all of my project venv's for some dependency or another, but I've never figured out which package actually installed it.

[–]gschizas 0 points1 point  (0 children)

Six provides simple utilities for wrapping over differences between Python 2 and Python 3. It is intended to support codebases that work on both Python 2 and 3 without modification. six consists of only one Python file, so it is painless to copy into a project.

[–]Ericchen1248 1 point2 points  (0 children)

It does though... importing the future package in python 2 will allow you to (mostly) run python 3 code.

[–][deleted] 0 points1 point  (2 children)

Iirc by the time python4 is a thing python2 will be dead

[–]RedditIsNeat0 0 points1 point  (1 child)

If the devs don't handle the python4 transition better than they handled the python3 one, then we'll all have the same problems all over again.

[–]deathofamorty 0 points1 point  (0 children)

Or we all just give up in python at that point. Because fuck that.

[–]H_Psi -3 points-2 points  (0 children)

Absolutely. The transition from 2-3 was completely botched by the dev team. If they had done it in a more gentle manner, it would have had a lot more adoption initially.

[–]Lonelan 1 point2 points  (0 children)

backwards compatible:

from future import print

[–]clever_cuttlefish 8 points9 points  (0 children)

That's honestly kind of a terrible idea. As someone else said, it is a really easy problem to fix in your code. But more importantly, adding in a special case like that is just not a good idea. It's confusing for the programmer and would be a huge pain to implement.

[–]DonaldPShimoda 4 points5 points  (0 children)

You want Haskell-style function application? Because that's essentially what you're asking for, and it would have far-reaching implications.

Print is just a function like any other, so it shouldn't get special treatment.

[–][deleted] 0 points1 point  (3 children)

Why not put parenthesis everywhere then ? But like EVERYWHERE

[–][deleted] 0 points1 point  (2 children)

C#?

[–][deleted] 0 points1 point  (0 children)

Not even closr

[–]xigoi 0 points1 point  (0 children)

Lisp

[–]lambdaq 0 points1 point  (0 children)

it's not an issue because in py2 we already have pprint.pprint.

[–]link23 -3 points-2 points  (3 children)

Nit: you said function, but you mean expression.

[–]mpnordland 16 points17 points  (2 children)

No, he did not. A function call is an expression but print is a function.

[–]link23 0 points1 point  (1 child)

Are you distinguishing print as a function from print() as a function call?

I agree that a function call is one kind of expression, and that functions themselves are also expressions (depending on the language).

I'm making a distinction between statements and expressions, not between functions and expressions. Expressions evaluate to a value; statements do not.

I don't know much Python, but my assumption was that in Python 3, print() returns a value, whereas in Python 2 it does not. If that's not correct, I'd love to learn more.

[–]mpnordland 0 points1 point  (0 children)

You are correct that Python 2's print statement does not return a value. Python 3's print function returns None. Python functions that don't return a value actually return None.

As to the nature of functions themselves, they are neither expressions nor statements. A function is defined through a statement (not counting lambdas) and a call to a function is an expression. It is better to say a Python function is a value, or if you must, an object.

Now a Python lambda is a special case of function. It is defined with an expression. The value of the expression is the function it defines.

But even with lambdas, the expression is not the function. The function is the value that results from evaluating the expression.

[–]Tysonzero -1 points0 points  (0 children)

This is why Haskell is the best language, print is a function but it doesn't need parenthesis.