Search code examples
pythontuplesoperator-precedenceiterable-unpackingorder-of-execution

Priority of tuple (un)packing with inline if-else


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?


Solution

  • 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.