Populate a list with a for loop :
nums = [12, 8, 21, 3, 16] new_nums = [] for num in nums: new_nums.append(num + 1) print(new_nums) -> [13, 9, 22, 4, 17]
We can do that in only one line with a list comprehension !
nums = [12, 8, 21, 3, 16] new_nums = [num + 1 for num in nums] print(new_nums) -> [13, 9, 22, 4, 17]
Now a list comprehension with range() :
result = [num for num in range(11)] print(result) -> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
List comprehensions :
- Collapse for loops for building lists into a single line
Components :
- iterable
- iterator variable (represent members of iterable)
- Output expression
Nested loops :
pairs_1 = [] for num1 in range(0, 2): for num2 in range(6, 8): pairs_1.append(num1, num2) print(pairs_1) -> [(0, 6), (0, 7), (1, 6), (1, 7)]
How to do it now with a list comprehension
pairs_2 = [(num1, num2) for num1 in range(0, 2) for num2 in range(6,8)] print(pairs_2) -> [(0, 6), (0, 7), (1, 6), (1, 7)]
The tradeoff is readibility as it is a bit difficult to understand the line.
Some examples from the exercises :
# Create list comprehension: squares squares = [num**2 for num in range(10)] # Create a 5 x 5 matrix using a list of lists: matrix matrix = [[col for col in range(5)] for row in range(5) ] # Print the matrix for row in matrix: print(row) -> [0, 1, 2, 3, 4] [0, 1, 2, 3, 4] [0, 1, 2, 3, 4] [0, 1, 2, 3, 4] [0, 1, 2, 3, 4]
Advanced comprehensions
Conditionals in comprehensions :
[num ** 2 for num in range(10) if num % 2 == 0] -> [0, 4, 16, 36, 64]
Conditionals on the output expression
[num ** 2 if num % 2 == 0 else 0 for num in range(10)] -> [0, 0, 4, 0, 16, 0, 36, 0, 64, 0]
Dict comprehensions
Use curly braces {} instead of brackets []
You put the key first then : and then the value you want to put
pos_neg = {num: -num for num in range(9)} print(pos_neg) {0: 0, 1: -1, 2: -2, 3: -3, 4: -4, 5: -5, 6: -6, 7: -7, 8: -8}
From the exercises
# Create a list of strings: fellowship fellowship = ['frodo', 'samwise', 'merry', 'aragorn', 'legolas', 'boromir', 'gimli'] # Create list comprehension: new_fellowship new_fellowship = [member for member in fellowship if len(member)>=7] # Print the new list print(new_fellowship) # Create a list of strings: fellowship fellowship = ['frodo', 'samwise', 'merry', 'aragorn', 'legolas', 'boromir', 'gimli'] # Create dict comprehension: new_fellowship new_fellowship = {member:len(member) for member in fellowship} # Print the new dictionary print(new_fellowship)
Generator expressions
To use generators, you basically do like a list comprehension but you use ( ) instead of brackets [ ]
(2 * num for num in range(10)) -><generator object <genexpr> at 0x1046bf888>
List comprehensions vs generators
- List comprehensions – returns a list
- Generators – returns a generator object
- Both can be iterated over
Printing values from generators
result = (num for num in range(6)) for num in result: print(num) -> 0 1 2 3 4 5 result = (num for num in range(6)) print(list(result)) -> [0, 1, 2, 3, 4, 5]
it’s a bit like when we talked about iter( ). we can use a generator to stock a very big number :
[num for num in range(10**10000)] -> Your session has been disconnected (num for num in range(10**100000)] <generator object..
Conditions in generator expressions
even_nums = (num for num in range(10) if num % 2 == 0) print(list(even_nums)) -> [0, 2, 4, 6, 8]
Generator functions
- Produces generator objects when called
- Defined like a regular function – def
- Yields a sequence of values instead of returning a single value
- Generates a value with yield keyword
Build a generator function :
def num_sequence(n): """Generate values from 0 to n.""" i = 0 while i < n: yield i i += 1
Use a generator function :
result = num_sequence(5) print(type(result)) -> <class 'generator'> for item in result: print(item) 0 1 2 3 4
From exercises : we can loop on a list to create a generator
# Create a list of strings: lannister lannister = ['cersei', 'jaime', 'tywin', 'tyrion', 'joffrey'] # Create a generator object: lengths lengths = (len(person) for person in lannister) # Iterate over and print the values in lengths for value in lengths: print(value)
And now with a function with a yield :
# Create a list of strings lannister = ['cersei', 'jaime', 'tywin', 'tyrion', 'joffrey'] # Define generator function get_lengths def get_lengths(input_list): """Generator function that yields the length of the strings in input_list.""" # Yield the length of a string for person in input_list: yield len(person) # Print the values generated by get_lengths() for value in get_lengths(lannister): print(value)
RECAP
Basic [output expression for iterator variable in iterable] Advanced [output expression + conditional on output for iterator variable in iterable + conditional on iterable]