At the moment we've only seen how to store and manipulate different types of variable. Now we'll see how to loop and use if-else statements in Python.
In [1]:
    
a = 1
if a == 1:
    print("a = 1")
    b = a + 2  # Indentation level indicates scope of 'if'
elif a == 2:  # Optionally can have 'elif' or 'else' statements 
    print("a = 2")
else:  # 
    print("a could be almost anything")
print(b)
    
    
a was defined outside of the if-else block. But b was defined inside the indented block and is still accessible outside the block.If-else blocks don't have their own variable scope.and, or, not rather than the boolean operators &&, ||, !is keyword as before, or a new one in. This lets you check if an element is in an iterable object like a list.
In [2]:
    
a = True
b = False
if a or b:
    print("a or b")
elif a and b:
    print("a and b")
elif a and not b:
    print("a and not b")
else:  # No
    print("Failed all somehow")
    
    
In [3]:
    
l = ["a", "b", "c"]
if "d" not in l:  # Don't have to loop and check each elemnt for elem == 'd'
    print("Hooray!")
    
    
if.
In [4]:
    
a = ""
if a:
    print("Variables can be true")
else:
    print("Or false")
    
    
0->n-1 and pick out the value each element of the array.for loops start at the 0th index and progress forwards until they reach the last element, then they end.
In [5]:
    
a = ["a", "c", "e", "d", "b"]
for elem in a:    # Simple for loop, variable 'elem' is the element currently reached
    print(elem, end=" ")  # I'm changeing the newline at the end of the print for a space
    
    
In [6]:
    
for elem in reversed(a):   # Can loop in reverse order
    print(elem, end=" ")
    
    
In [7]:
    
for i,elem in enumerate(a):   # Use enumerate() if you want the index and the element
    print(i, elem)
    
    
i and elem. The enumerate function and for loop are actually returning tuples with the 0th element being the index of the current element, and the second being the element itself.i,elem unpacks the values inside this implicit tuple into the two variables during each iteration.
In [8]:
    
for elem in sorted(a):  # Can sort in an obvious way, then iterate
    print(elem, end=" ")
print()
print(a)   # Note that the sorted() function made a copy and didn't affect the list.
a.sort()   # list.sort() DOES re-order the elements in place.
print(a)
    
    
sorted() function is much more flexible though. It can take key functions as an argument to give you a custom sort order.
In [9]:
    
a = ["Dave", "Andy", "Charlotte", "Emma", "Darcey", "Rob"]
print(len(a))   # The built in len() function takes an iterable and gives you its length
for elem in sorted(a, key=len):   # Will iterate by length of string
    print(elem)
    
    
zip() function.
In [10]:
    
a = ["Dave", "Andy", "Charlotte", "Emma", "Darcey", "Rob"]
b = ["Handsome", "Uggo", "Busy"]
# Note the two lists are different lengths
for name,adjective in zip(a,b):  # Zip is fast and memory efficient
    print(adjective,name)
print(list(zip(a,b)))  # Zip dosn't generate a container until you want one
    
    
range() function.range() function takes the arguments range( start, stop, step ) where start and step are optional. You can give only the stopping value and you get the integers from 0->(stop-1).
In [11]:
    
for i in range(10):   # The range() function gives you iterators for a sequence you define
    print(i, end=" ")
    
    
In [12]:
    
for i in range(9, -1, -1):  # Start at 9, decrease by 1 and stop looping when hitting -1.
    print(i, end=" ")
print()
for i in range(0, 20, 3):   # Start at 0, increase by 3 and stop looping when hitting 20.
    print(i, end=" ")
    
    
In [13]:
    
l = list(range(10))  # Can use range to rapidly make lists/tuples/etc of sequences.
print(l)
    
    
list(range(10)) above to make the list, because although the object returned by range() behaves like a list in a loop, it isn't one in Python 3!range() and functions like it return each value sequentially without making the full list object until you explicitly make it with the list() function. This means you can safely loop over use enormous ranges/zips without running out of memory.
In [14]:
    
d = {"Dave":27, "Andy":28, "Emma":4, "Darcey":2}
for k in d:  # Looping directly over the dictionary gives you the keys
    print(k)
    
    
In [15]:
    
# Need to use methods of dictionary to get at values or key-value pairs
items = d.items()
keys = d.keys()
values = d.values()
for it,k,v in zip(items, keys, values):  # Don't assume these objects have the same order!
    print(k,v,it)
    
    
[].for loops return elements for use in each iteration you can imagine generating a new list by inserting the for loop inside the brackets.
In [16]:
    
l = list(range(10))  # Make a quick list
l_sq = [elem**2 for elem in l]  # Square the elements and put the result into the new list
print(l)
print(l_sq)
    
    
for loop. After that you can add many more for loops or even if statements, in the same order as if they were ordinary loops.
In [17]:
    
l_odd =[ elem for elem in l if (elem%2) != 0 ]  # Only add odd numbers
print(l_odd)
    
    
In [18]:
    
vec = [(1,2,3), (4,5,6), (7,8,9)]  # Let's flatten this
l_flat = [ num for elem in vec for num in elem ]  # Nested loops
print(l_flat)
    
    
break, continue, pass and else statements.
In [19]:
    
for i in range(10):
    pass   # Used when there's nothing else to be put here
    
In [20]:
    
for i in range(10):
    print(i, end=" ")
    if i==5:
        break   # Exits the loop at this point
    
    
In [21]:
    
for i in range(10):
    if (i%2)==0:  # Check for even numbers
        continue  # Progresses to next iteration missing rest of loop block
    print("An odd number",i)
    
    
for loop. Either the loop ends normally or it hits a break statement that ends it early.for loops had an implicit if and goto embedded in them i.e. If I haven't reached the end condition of the loop goto the beginning and loop again.for loops in Python can use an else statement after them which is only run if the for loop finished without a break statement.
In [22]:
    
for i in range(10):
    print(i, end=" ")
    if i==15:
        break
else:
    print("\nMade it to the end!")
    # Note that the 'else' is connected to the 'for' not the 'if'
    
    
While loops are much the same as they always are.
In [23]:
    
a = 0
while a < 10:
    print(a, end=" ")
    a+=1
    
    
for loops you can use pass, break, continue and even the else clause with while loops i.e. If the loop exits without using a break statement the else code will be run.
In [24]:
    
a = 0
while a < 10:
    print(a, end=" ")
    if a == -1:
        break
    a+=1
else:
    print("\nCan't break this!")