List comprehension and generator expressions

List comprehension and generator expressions are important Python features that allows you to do implicit enumeration in a concise fashion. To give a simple example, the following list comprehension builds a list containing the squares of the numbers from 1 through 5:

gurobi> [x*x for x in [1, 2, 3, 4, 5]]
[1, 4, 9, 16, 25]
A generator expression is very similar, but it is used to generate an Iterable (something that can be iterated over). For example, suppose we want to compute the sum of the squares of the numbers from 1 through 5. We could use list comprehension to build the list, and then pass that list to sum. However, it is simpler and more efficient to use a generator expression:
gurobi> sum(x*x for x in [1, 2, 3, 4, 5])
55
A generator expression can be used whenever a method accepts an Iterable argument (something that can be iterated over). For example, most Python methods that accept a list argument (the most common type of Iterable) will also accept a generator expression.

Note that there's a Python routine for creating a contiguous list of integers: range. The above would typically be written as follows:

gurobi> sum(x*x for x in range(1,6))
Details on the range function can be found here.

List comprehension and generator expressions can both contain more than one for clause, and one or more if clauses. The following example builds a list of tuples containing all x,y pairs where x and y are both less than 4 and x is less than y:

gurobi> [(x,y) for x in range(4) for y in range(4) if x < y]
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
Note that the for statements are executed left-to-right, and values from one can be used in the next, so a more efficient way to write the above is:
gurobi> [(x,y) for x in range(4) for y in range(x+1, 4)]

Generator expressions are used extensively in our Python examples, primarily in the context of the addConstrs method.