Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the comma doing in this assignment? [duplicate]

I am not very familiar with Python syntax, and was wondering if anyone can explain to me how the variable match is taking on a string found inside the for expression in this function:

def find_project(project_name):    
    projects = get_projects()    
    try:
        match, = (proj for proj in projects if proj["name"].strip() == project_name)
        return match
    except ValueError:
        return None
like image 834
j.doe Avatar asked Sep 12 '25 07:09

j.doe


1 Answers

Python allows you to assign more than one variable at once, like this:

a, b = 1, 2

The way this works is by treating the left hand side of the assignment a, b as a tuple, and assigning each element in the tuple 1, 2 on the right hand side to it.

Since tuples can have just one element, the following also works:

a, = 1,

The right hand side of a multiple assignment doesn't have to be a tuple. Any iterable will do, as long as the number of elements on each side is the same:

a, b, c = "three little pigs".split()

If the number of elements doesn't match:

a, b, c = "oh", "no"

... you get a ValueError:

ValueError: not enough values to unpack (expected 3, got 2)

Putting all of the above together, then, your function:

def find_project(project_name):    
    projects = get_projects()    
    try:
        match, = (proj for proj in projects if proj["name"].strip() == project_name)
        return match
    except ValueError:
        return None

... iterates over the generator expression

(proj for proj in projects if proj["name"].strip() == project_name)

... and if the result has one element, assigns that element to match. If not, ValueError is raised (and caught by the except clause), no assignment happens, and None is returned .

Two things to note:

  1. The comma , is easy to miss when reading code. An alternative would be to use list syntax on the left hand side:

    [match] = (proj for proj in projects if proj["name"].strip() == project_name)
    

    ... which has the same effect.

  2. When the right hand side is a generator expression (or some other kind of iterator), you can use next() with a default value instead:

    def find_project(project_name):    
        projects = get_projects()    
        it = (proj for proj in projects if proj["name"].strip() == project_name)
        return next(it, None)
    

    ... which is shorter and more readable.

like image 145
Zero Piraeus Avatar answered Sep 14 '25 19:09

Zero Piraeus