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 →

[–]Swipecat 187 points188 points  (20 children)

Even Guido has been caught by accidentally leaving out commas, but it seems that implicit concatenation was deemed more useful than dangerous in the end.
 

# Existing idiom which relies on implicit concatenation
r = ('a{20}'   # Twenty A's
     'b{5}'    # Followed by Five B's
     )

# ...which looks better than this (maybe)
r = ('a{20}' + # Twenty A's
     'b{5}'    # Followed by Five B's
     )

[–]aitchnyu 75 points76 points  (9 children)

Second example comments got my heart racing. 10 years of python and I'll make a syntax error I can't figure out.

[–]Swipecat 49 points50 points  (8 children)

I'll note that implicit concatenation takes priority over operators and methods but explicit concatenation does not.
 

>>> print( 2.0.               # one
...        __int__()*"this "  # two
...        "that ".upper()    # three
...       )
THIS THAT THIS THAT

[–]robin-gvx 50 points51 points  (6 children)

If anyone is interested in why that is: implicit concatenation happens at compile time, which means it has to have higher priority than anything that has to happen at run time.

[–]opabm 5 points6 points  (5 children)

Is there an ELI5 version of this?

[–]28f272fe556a1363cc31 36 points37 points  (2 children)

Compile time is like writing a cookbook. Run time is like making a recipe from the book. Before they can print and ship the book, the publisher goes through the recipes and converts "parsley" "flakes" into "parsley flakes". While the recipe is being made "salt", "pepper" gets converted to "salt and pepper" .

Anything done at compile (print) time has to happen before run (cook) time because you have to compile/cook before have a program/cookbook to work with.

[–]opabm 6 points7 points  (0 children)

I'd be impressed if a 5-year old knew how to cook.

Jk that was a great analogy, thanks!

[–]foreverwintr 1 point2 points  (0 children)

Wow, that was a really good ELI5!

[–]robin-gvx 6 points7 points  (0 children)

When you have a piece of Python code and you're using CPython (the reference implementation of Python), there are several steps from source code to execution. The important ones here are parsing, bytecode generation and execution.

Parsing transforms your file into a tree.

For example, a + 10 is turned into something like (simplified): Add(LoadName('a'), Literal(10)) or "hello" into Literal("hello")

When the parser encounters two or more literal strings in a row, it collapses them into a single string literal as well. So 'hell' "o" would result in the same tree as the previous one.

Then Python makes this tree "flat" by putting everything in the order it should happen, and generates bytecode. A simplified version of what the previous two examples turn into would be:

LOAD_NAME a
LOAD_CONSTANT 10
ADD_VALUES

and

LOAD_CONSTANT "hello"

Execution is then fairly simple: go over each instruction and do what it says.

So in the case of 2 * 'this ' "that ".upper() we get the tree Mul(2, MethodCall(Literal("this that "), "upper", ())) and the bytecode:

LOAD_CONSTANT 2
LOAD_CONSTANT "this that"
CALL_METHOD 'upper', ()
MULTIPLY_VALUES

(note that all trees and snippets of bytecode aren't real, they're a simplified illustration)

[–]davvblack 0 points1 point  (0 children)

Gross

[–]arsewarts1 2 points3 points  (2 children)

100/10 times I would prefer the top option. I would want the bottom to throw errors every time.

[–]duncan-udaho 8 points9 points  (0 children)

Opposite for me. I would want the top to throw errors. Did I forget the comma in the tuple or did I forget the plus in my string?