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