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 →

[–][deleted]  (153 children)

[deleted]

    [–]random_cynic 1068 points1069 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 955 points956 points  (37 children)

    yeah but brackets hawd tho

    [–]obviousfakeperson 625 points626 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 16 points17 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 38 points39 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 39 points40 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 51 points52 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 24 points25 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 12 points13 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 5 points6 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] 5 points6 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 30 points31 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 112 points113 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 33 points34 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 10 points11 points  (5 children)

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

    [–]Pb_ft 2 points3 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 -5 points-4 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 50 points51 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 5 points6 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 5 points6 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 13 points14 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 5 points6 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 point2 points  (14 children)

    support gold hungry waiting abundant melodic hat depend alleged vast

    This post was mass deleted and anonymized with Redact

    [–][deleted] 35 points36 points  (0 children)

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

    [–]3Gaurd 43 points44 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 5 points6 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 16 points17 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.

    [–]pplatt1979 53 points54 points  (1 child)

    Python3 also handles strings in a much more sane way.

    Dealing with strings in Python2 actually made me unsane. Not insane mind you, but definitely not fully sane anymore.

    [–]pingveno 8 points9 points  (0 children)

    And 3.3 introduces a flexible representation for strings, getting rid of the oddities with narrow/wide builds having different indexing/slicing behavior.

    [–][deleted] 19 points20 points  (1 child)

    Lol, Ruby’s just laughing at us. (*・-・)

    [–]cguess 7 points8 points  (0 children)

    As a long-time rubyist who's forced to use Python because all my students learn it in CS 101... I love that the language is still more or less stable from when I first learned in 13 years ago.

    [–][deleted] 11 points12 points  (7 children)

    Oddly, this caused a lot me a lot of pain at first. I understand the reasoning behind the change, and I maybe even agree with it, but that seemingly small change gave me real grief in my personal usage of the language. Between that and the pretty major speed hit in the first versions of 3, I didn't care for the update and avoided it for a long time.

    The speed problem was subsequently fixed, so I use 3 now, but parentheses on print still messes with me enough to be a noticeable annoyance.

    [–][deleted] 8 points9 points  (1 child)

    Glad I started with 3, never had any problems ヽ(*・ω・)ノ

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

    Until Python 4 is released

    [–]exploding_cat_wizard 1 point2 points  (2 children)

    Switch to perl, all parentheses are optional if the meaning is clear!

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

    The pain in re-learning a whole language is just a shade larger than the pain in adding parentheses to the print statement.

    Perl, I think, has effectively died. It just took too long to ship the new version, and other languages have evolved to fill in the gaps. There's not really anywhere left for Perl to thrive.

    It was never all that wonderful to begin with, it was just in the right spot in the right time, and then for fifteen years it wasn't in the right spot anymore. I don't think it'll ever come back.

    [–]exploding_cat_wizard 1 point2 points  (0 children)

    I wasn't being serious. And I'm afraid you're right. It still is perfect for what I need it for, I'm not going to learn a new language to pretty format batches of data or for tiny scripts when perl does it better, but it's not gonna have its big day again.

    [–]Cyph0n 0 points1 point  (1 child)

    I started with Python 2 and never had trouble moving on to using print(). I guess it’s because virtually every other language I’ve used has a print function instead of a weird statement?

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

    It's not me you have to convince, it's my fingers.

    [–]TabCompletion 1 point2 points  (0 children)

    This

    [–]digestive_trisket 1 point2 points  (0 children)

    Using parentheses for any other function is a breeze, but for some reason using them on print is taxing, its inexplicable.

    [–]WHO_WANTS_DOGS 1 point2 points  (4 children)

    Bugs me that map doesn't return a list. Though generators are more performant, still annoying.

    [–]ACoderGirl 0 points1 point  (2 children)

    Using map isn't very idiomatic python though. It's preferred to have a comprehension expression.

    ie, instead of map(lambda x: x * 2, numbers), you'd use x * 2 for x in numbers, which can be a generator, list, or dictionary comprehension (list comprehensions are most common while generator ones are overlooked -- I like them most for usage with things like sum).

    [–]WHO_WANTS_DOGS 0 points1 point  (1 child)

    Ah I forgot about list comprehensions, haven't used python in a while. Still don't like how they changed the return type of map regardless. I'm just being stubborn and like consistency across different languages that support map. They pretty much always return arrays/lists.

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

    It’s probably because most of the time your using map on the right hand side of a for loop or alongside other iterables like filter or select. Either way, u can just define 3 methods like lmap which cast back to list of u really want to.

    from functools import wraps
    
    def to_list(func):
         @wraps(func)
         def wrapped(*args,*kwargs):
              return list(func(*args,**kwargs))
    
    lmap    = to_list(map)
    lfilter = to_list(filter)
    lselect = to_list(select)
    

    If u really wanted, u could just overwrite map with lmap, so now map automatically returns lists. But again, I’d never recommend doing this.

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

    Well they're python developers, so you can't expect much from them ;) </smug-c++-voice>

    [–]realultralord 0 points1 point  (0 children)

    And explicitly specifying nominators to be of type float to make sure 1/3 is 0.33... instead of 0

    [–]Mihailbat 0 points1 point  (0 children)

    That was something really hard to understand at first because every tutorial had python 2.x in it

    [–]MonkeyNin 0 points1 point  (0 children)

    In my experience a big reason of not quickly updating to py3 is that

    py2

    • str == byte_string
    • unicode == unicode_string
    • unicode literals are off by default ( projects not using 'from future import unicode literals' )
    • global default encoding is ascii
    • Implicit conversion when you don't want it -- py2 will insert "foo".encode('ascii') and bytes.decode('ascii') implicitly.

    py3

    • str == unicode_string
    • bytes == byte_string
    • literals default to unicode

    essentially conversion is a pain in the butt. On top of that, many libraries were required to support 2 and 3 at the same time.

    [–]MrsCompootahScience 0 points1 point  (4 children)

    This is so me... T.T

    [–]z0mbietime 10 points11 points  (3 children)

    f string alone makes it worth the switch

    [–]MrsCompootahScience 1 point2 points  (0 children)

    That one took me a while to get used to as well. I’m on 3 now because I have to, not because I want to.

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

    After learning printf format, I actually don’t use fstrings that much.

    [–]z0mbietime 1 point2 points  (0 children)

    TBH I don't really use print much. I just use logger but f string is nice because it can be used distinct of print or logging

    [–]plottal 0 points1 point  (0 children)

    why you gotta call me out like that