In part 13 of my Learn to Program tutorial we’ll be covering some very powerful Python tools. We’ll look at Iterables, List Comprehensions, Generator Functions and Generator Expressions. List Comprehensions have the power of Map and Filter all in one place. Also there are a bunch of problems for us to solve.

If you missed the previous videos they start here. A cheat sheet as well as a transcript from the video follow the video below.

If you value videos like this consider donating a $1 on Patreon.

**Code & Transcript**

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# ---------- ITERABLES ---------- # An iterable is a stored sequence of values (list) or, # as we will see when we cover generators, an # object that produces one value at a time # Iterables differ from iterators in that an iterable # is an object with an __iter__ method which returns # an iterator. An iterator is an object with a # __next__ method which retrieves the next value from # sequence of values # Define a string and convert it into an iterator sampStr = iter("Sample") print("Char :", next(sampStr)) print("Char :", next(sampStr)) # You can add iterator behavior to your classes class Alphabet: def __init__(self): self.letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" self.index = -1 def __iter__(self): return self def __next__(self): if self.index >= len(self.letters) - 1: raise StopIteration self.index += 1 return self.letters[self.index] alpha = Alphabet() for letter in alpha: print(letter) # Iterate through a dictionary because it is an iterable derek = {"fName": "Derek", "lName": "Banas"} for key in derek: print(key, derek[key]) # ---------- PROBLEM ---------- # Create a class that returns values from the Fibonacci # sequence each time next is called # Sample Output # Fib : 1 # Fib : 2 # Fib : 3 # Fib : 5 class FibGenerator: def __init__(self): self.first = 0 self.second = 1 def __iter__(self): return self def __next__(self): fibNum = self.first + self.second self.first = self.second self.second = fibNum return fibNum fibSeq = FibGenerator() for i in range(10): print("Fib :", next(fibSeq)) # ---------- LIST COMPREHENSIONS ---------- # A list comprehension executes an expression against an iterable # Note: While they are super powerful, try not to make list # comprehensions that are hard to figure out for others # To multiply 2 times every value with a map we'd do print(list(map((lambda x: x * 2), range(1, 11)))) # With a list comprehension we'd do # Note that a list comprehension is surrounded by [] # because it returns a list print([2 * x for x in range(1, 11)]) # To construct a list of odds using filter we'd print(list(filter((lambda x: x % 2 != 0), range(1, 11)))) # To do the same with a list comprehension print([x for x in range(1, 11) if x % 2 != 0]) # A list comprehension can act as map and filter # on one line # Generate a list of 50 values and take them to the power # of 2 and return all that are multiples of 8 print([i ** 2 for i in range(50) if i % 8 == 0]) # You can have multiple for loops as well # Multiply all values in one list times all values in # another print([x * y for x in range(1, 3) for y in range(11, 16)]) # You can put list comprehensions in list comprehensions # Generate a list of 10 values, multiply them by 2 and # return multiples of 8 print([x for x in [i * 2 for i in range(10)] if x % 8 == 0]) # ---------- PROBLEM ---------- # Generate a list of 50 random values between 1 and 1000 # and return those that are multiples of 9 # You'll have to use a list comprehension in a list comprehension # This is a hard one! import random print([x for x in [random.randint(1, 1001) for i in range(50)] if x % 9 == 0]) # List comprehensions also make it easy to work with # multidimensional lists multiList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] print([col[1] for col in multiList]) # Get the diagonal by incrementing 0, 0 -> 1, 1 -> 2, 2 print([multiList[i][i] for i in range(len(multiList))]) # ---------- GENERATOR FUNCTIONS ---------- # A generator function returns a result generator when called # They can be suspended and resumed during execution of # your program to create results over time rather then # all at once # We use generators when we want to big result set, but # we don't want to slow down the program by creating # it all at one time # Create a generator that calculates primes and returns # the next prime on command def isprime(num): # This for loop cycles through primes from 2 to # the value to check for i in range(2, num): # If any division has no remainder we know it # isn't a prime number if (num % i) == 0: return False return True # This is the generator def gen_primes(max_number): # This for loop cycles through primes from 2 to # the maximum value requested for num1 in range(2, max_number): if isprime(num1): # yield is what makes this a generator # When called by next it will return the # next result yield num1 # Create a reference to the generator prime = gen_primes(50) # Call next for each result print("Prime :", next(prime)) print("Prime :", next(prime)) print("Prime :", next(prime)) # ---------- GENERATOR EXPRESSIONS ---------- # Generator expressions look just like list comprehensions # but they return results one at a time # The are surrounded by parentheses instead of [ ] double = (x * 2 for x in range(10)) print("Double :", next(double)) print("Double :", next(double)) # You can iterate through all results as well for num in double: print(num) |

## Leave a Reply