6

Apologies in advance for the obscure title. I wasn't sure how to phrase what I encountered.

Imagine that you have a title of a book alongside its author, separated by -, in a variable title_author. You scraped this information from the web so it might very well be that this item is None. Obviously you would like to separate the title from the author, so you'd use split. But in case title_author is None to begin with, you just want both title and author to be None.

I figured that the following was a good approach:

title_author = "In Search of Lost Time - Marcel Proust"
title, author = title_author.split("-", 1) if title_author else None, None
print(title, author)
# ['In Search of Lost Time ', ' Marcel Proust'] None

But to my surprise, title now was the result of the split and author was None. The solution is to explicitly indicate that the else clause is a tuple by means of parentheses.

title, author = title_author.split("-", 1) if title_author else (None, None)
print(title, author) 
# In Search of Lost Time   Marcel Proust

So why is this happening? What is the order of execution here that lead to the result in the first case?

Bram Vanroy
  • 27,032
  • 24
  • 137
  • 239
  • `title_author.split("-", 1) if title_author else None, None` is a tuple, but the first element is the whole ternary expression `title_author.split("-", 1) if title_author else None` and the second element is `None`. – fsimonjetz Jul 03 '22 at 10:58
  • Tuples are generated from left to right without precedence (lower as ["lowest"](https://docs.python.org/3/reference/expressions.html#operator-precedence)), so the *priority* is `((title_author.split("-", 1)) if title_author else None), None` – Michael Szczesny Jul 03 '22 at 11:00
  • @MichaelSzczesny That was the information that I was looking for. If you have a source for that and can post it as an answer, I'll accept it. The current answers do not specify why this is the order in which the tuple is generated but I am looking for a source/explanation. – Bram Vanroy Jul 03 '22 at 11:03
  • 1
    Can you please clarify what you are looking for? The question already demonstrates the order of execution, so it's not clear what you expect on this. As for "why" - well, because that's the precedence, so again it's not clear what you expect here. Are you looking for the formal elements in use here? – MisterMiyagi Jul 03 '22 at 12:04

1 Answers1

4
title, author = title_author.split("-", 1) if title_author else None, None

is the same as:

title, author = (title_author.split("-", 1) if title_author else None), None

Therefore, author is always None


Explaination:

From official doc

An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.

That is to say, the interrupter will look for (x,y)=(a,b) and assign value as x=a and y=b.

In your case, there are two interpretation, the main differece is that :

  1. title, author = (title_author.split("-", 1) if title_author else None), None is assigning two values (a list or a None and a None) to two variables and no unpacking is needed.

  2. title, author = title_author.split("-", 1) if title_author else (None, None) is actually assigning one value (a list or a tuple) to two variable, which need an unpacking step to map two variables to the two values in the list/tuple.

As option 1 can be completed without unpacking, i.e. less operation, the interrupter will go with option 1 without explicit instructions.

ytung-dev
  • 872
  • 1
  • 2
  • 12
  • I figured that out, but _why_ is that the same? What are the rules in Python precedence that lead to that execution. I am looking for sources. – Bram Vanroy Jul 03 '22 at 11:20
  • @bram-vanroy If title is `None`, then author will be `None` too. You can't have a null book with an author – Cardstdani Jul 03 '22 at 11:25
  • That's not what I mean. My question is, how is it defined in Python internals that a tuple is formed from left to right before packing? How does Python now "I expect 2 items in the tuple, and so now I will try to generate a tuple from left to right". Where is this order specified. – Bram Vanroy Jul 03 '22 at 11:41
  • @BramVanroy Python doesn't know and especially doesn't care that you expect 2 items. Go ahead and make the same assignment with a target list of 0, 1 or 3. – MisterMiyagi Jul 03 '22 at 12:06
  • 1
    I feel like this answer would be even more useful if it were to point out that the left hand side isn't actually an expression, but a sequence of expressions. The "," is evaluated outside of an expressions precedence rules. – MisterMiyagi Jul 03 '22 at 12:09
  • Strictly speaking, unpacking happens in the first case too. According to the cited documentation, *single* object is assigned to the target list, which in both of our cases results in unpacking, as there's an assignment of iterable object on the rhs to a target list. – YurkoFlisk Jul 30 '22 at 08:44