Chapter 4 Control and Loops

4.1 If Statement

4.1.1 Multiline If.. Statements

price = 102
if price <100:
    print ('buy')
elif price < 110:
    print ('hold')
elif price < 120:
    print ('think about it')
else:
    print ('sell')
## hold
print('end of programming')
## end of programming

4.1.2 Single Line If .. Statement

4.1.2.1 if … In One Statement

price = 70
if price<80: print('buy')
## buy

4.1.2.2 Ternary Statemnt

This statement return a value with simple condition

price = 85
'buy' if (price<80) else 'dont buy'
## 'dont buy'

4.2 For Loops

4.2.1 For .. Else Construct

else is only executed when the for loop completed all cycles


mylist = [1,2,3,4,5]

for i in mylist:
  print (i)
else:
  print('Hooray, the loop is completed successfully')
## 1
## 2
## 3
## 4
## 5
## Hooray, the loop is completed successfully

In below exmaple, for loop encountered break, hence the else section is not executed.

for i in mylist:
  if i < 4:
    print (i)
  else:
    print('Oops, I am breaking out half way in the loop')
    break
else:
  print('Hooray, the loop is completed successfully')
## 1
## 2
## 3
## Oops, I am breaking out half way in the loop

4.2.2 Loop thorugh ‘range’

for i in range (1,10,2):
    print ('Odds Number : ',i) 
## Odds Number :  1
## Odds Number :  3
## Odds Number :  5
## Odds Number :  7
## Odds Number :  9

4.2.3 Loop through ‘list’

4.2.3.1 Standard For Loop

letters = ['a','b','c','d']
for e in letters:
    print ('Letter : ',e)
## Letter :  a
## Letter :  b
## Letter :  c
## Letter :  d

4.2.3.2 List Comprehension

Iterate through existing list, and build new list based on condition
new_list = [expression(i) for i in old_list]

s = ['abc','abcd','bcde','bcdee','cdefg']
[x.upper() for x in s]
## ['ABC', 'ABCD', 'BCDE', 'BCDEE', 'CDEFG']

Extend list comprehension can be extended with if condition**
new_list = [expression(i) for i in old_list if filter(i)]

old_list    = ['abc','abcd','bcde','bcdee','cdefg']
matching = [ x.upper() for x in old_list if 'bcd' in x ]
print( matching )
## ['ABCD', 'BCDE', 'BCDEE']

4.2.4 Loop Through ‘Dictionary’

Looping through dict will picup key

d = {"x": 1, "y": 2}
for key in d:
    print (key, d[key])
## x 1
## y 2

4.3 Generators

  • Generator is lazy, produce items only if asked for, hence more memory efficient
  • Generator is function with ‘yield’ instead of ‘return’
  • Generator contains one or more yields statement
  • When called, it returns an object (iterator) but does not start execution immediately
  • Methods like iter() and next() are implemented automatically. So we can iterate through the items using next()
  • Once the function yields, the function is paused and the control is transferred to the caller
  • Local variables and their states are remembered between successive calls
  • Finally, when the function terminates, StopIteration is raised automatically on further calls

4.3.1 Basic Generator Function

Below example give clear understanding of how generator works

def my_gen():
    n = 1
    print('This is printed first')
    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n
a = my_gen()
type(a)
## <class 'generator'>
next(a)
## This is printed first
## 1
next(a)
## This is printed second
## 2

4.3.2 Useful Generator Fuction

Generator is only useful when it uses for-loop - for-loop within generator - for-loop to iterate through a generator

def rev_str(my_str):
    length = len(my_str)
    for i in range(length - 1,-1,-1):
        yield my_str[i]
for c in rev_str("hello"):
     print(c)
## o
## l
## l
## e
## h

4.3.3 Generator Expression

Use () to create an annonymous generator function

my_list = [1, 3, 6, 10]
a = (x**2 for x in my_list)
next(a)
## 1
next(a)
## 9
sum(a) # sum the power of 6,10
## 136

4.3.4 Compare to Iterator Class

class PowTwo:
    def __init__(self, max = 0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n > self.max:
            raise StopIteration

        result = 2 ** self.n
        self.n += 1
        return result

Obviously, Generator is more concise and cleaner

def PowTwoGen(max = 0):
    n = 0
    while n < max:
        yield 2 ** n
        n += 1