Python Training at VMWare Pune - Day 2

Oct 16-18, 2017 Vikrant Patil

These notes are available online at http://notes.pipal.in/2017/vmware-oct-python

© Pipal Academy LLP

Day 1 | Day 2 | Day 3

while loop

In [1]:
def print_fibonacci(n):
    """
    print fibionacci numbers less than n
    """
    
    prev, current = 1, 1
    
    while current < n:
        prev, current = current, prev+current
        print(prev, end=",")
In [2]:
print_fibonacci(1000)
1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,

Lets print first n natural numbers using while loop!

In [5]:
def print_naturals(n):
    k = 1
    while k <=n:
        print(k, end=",")
        k += 1
In [6]:
print_naturals(20)
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,

for loop

In [7]:
names = ["Elsa", "David", "Mahesh", "Hari"]
In [8]:
for name in names:
    print(name)
Elsa
David
Mahesh
Hari
In [9]:
for f in [1,2,3,5,8,13,21,34,55,89,144,233,377,610,987]:
    print(f, end=",")
1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
In [10]:
for c in "This statement is for testing for loop":
    print(c, end=",")
T,h,i,s, ,s,t,a,t,e,m,e,n,t, ,i,s, ,f,o,r, ,t,e,s,t,i,n,g, ,f,o,r, ,l,o,o,p,

what is I want a usual for loop?

In [11]:
for i in range(5):
    print(i, end=",")
0,1,2,3,4,
In [13]:
for i in range(2, 20, 2):
    print(i, end=",")
2,4,6,8,10,12,14,16,18,

problem:

  • Write a program ls.py to list files in current directory
  • Write a function mysum that sums up numbers from given list.
    >>> mysum([1,1,1,1])
    4
  • Write a function product that computes product of all elements from a list
    >>> product([2,3,4])
    24
  • Write a function factorial that computes factorial of a given number
    >>> factorial(4)
    24
    Bonus problem:
  • Write a function sumdigits to find sum of digits of a given number
  • Write a function reordermax which rearranges digits of a number to from a max number.
In [15]:
def product(numbers):
    p = 1 
    for n in numbers:
        p = p * n
    return p
In [16]:
product([1,2,3])
Out[16]:
6
In [17]:
def factorial(n):
    return product(range(1, n+1))
In [18]:
factorial(5)
Out[18]:
120

There is a break statement as well

In [19]:
def print_primes(n):
    """
    prints all prime numbers less than n
    """
    
    for i in range(2, n):
        for j in range(2,i):
            if i%j == 0:
                break
        else:
            print(i, end=",")
In [20]:
print_primes(50)
2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,

problem : write a function prime_fibinacci to print fibonacci numbers less than n but are prime numbers also

In [24]:
def prime_fibonacci(n):
    """
    prints numbers less than n that are prime and fibinacci numbers
    """
    
    prev, current = 2, 3
    
    while prev < n:
        for i in range(2, prev): # test primality
            if prev%i == 0:
                break
        else:
            print(prev, end=",")

        prev, current = current, prev+current # fibinacci computation
In [25]:
prime_fibonacci(100)
2,3,5,13,89,

Recap list methods

In [26]:
range(5)
Out[26]:
range(0, 5)
In [27]:
list(range(5))
Out[27]:
[0, 1, 2, 3, 4]
In [28]:
numbers = list(range(10))
In [29]:
numbers
Out[29]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [30]:
numbers.append(11)
In [31]:
numbers
Out[31]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11]
In [32]:
numbers.insert(0, -1)
In [33]:
numbers
Out[33]:
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11]
In [34]:
numbers.pop(0)
Out[34]:
-1
In [35]:
numbers
Out[35]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11]
In [36]:
numbers.index(4)
Out[36]:
4
In [37]:
emptylist = []

problem:

  • Write a function square which squares in a list
    >>> square([2,3,4,5]
    [4,9,16,25]
  • Write a function evens to find out even numbers for a list of numbers

    >>> evens([1,2,3,4,6,7,8,9])
    [2,4,6,8]
  • Modify above function prime_fibonacci to return a list of primes fibonacci numbers instead of printing

    >>> prime_fibonacci(100)
    [2,3,5,13,89]
In [38]:
def double(numbers):
    d = []
    for n in numbers:
        d.append(2*n)
    return d
In [39]:
double([2,4,5])
Out[39]:
[4, 8, 10]

list slicing

In [40]:
digits = list(range(10))
In [41]:
digits
Out[41]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [42]:
digits[1:6] # new list containing items from index 1(included) till 6(excluded)
Out[42]:
[1, 2, 3, 4, 5]
In [43]:
digits[1:] #new list containing items from 1 till end
Out[43]:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
In [44]:
digits[:5] # from start (0) to index 5(excluded)
Out[44]:
[0, 1, 2, 3, 4]
In [45]:
digits[-1]
Out[45]:
9
In [46]:
digits[:-1] # all items except last
Out[46]:
[0, 1, 2, 3, 4, 5, 6, 7, 8]
In [47]:
digits[:] # just copy of list
Out[47]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [48]:
digits[2:7:2] # start from index 2(included) till index 7(excluded) but at interval of 2
Out[48]:
[2, 4, 6]
In [49]:
digits[::-1] # reverse of list
Out[49]:
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [50]:
word = "madam"
In [51]:
word == word[::-1]
Out[51]:
True
In [52]:
is_palindrome = lambda word: word == word[::-1]
In [53]:
is_palindrome
Out[53]:
<function __main__.<lambda>>
In [54]:
type(is_palindrome)
Out[54]:
function
In [55]:
is_palindrome("civic")
Out[55]:
True
In [56]:
is_palindrome("hello")
Out[56]:
False
In [57]:
square = lambda x: x*x
In [58]:
square(2)
Out[58]:
4
In [59]:
add = lambda x, y: x+y
In [60]:
add(2, 3)
Out[60]:
5

problem :

  • write a function split_at which takes a list and index (integer) as argument. It splits given list in two lists , first list is left side of index and second list is right side of index
    >>> split_at([0,1,2,3,4,5,6,7,8,9], 2)
    ([0,1], [2,3,4,5,6,7,8,9])
  • Write a function find_extension which finds extension of a file given file name.
    >>> find_extension("python.exe")
    exe
  • What might be output of this?
    >>> s = "Do geese see God?"
    >>> s[100]
    >>> s[3:100]

List comprehensions

In [61]:
numbers = range(10)
In [62]:
nums = [n for n in numbers]
In [63]:
nums
Out[63]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [64]:
squares = [n*n for n in numbers]
In [65]:
squares
Out[65]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
In [66]:
cubes = [n**3 for n in numbers]
In [67]:
cubes
Out[67]:
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
In [68]:
[factorial(n) for n in numbers]
Out[68]:
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]

Convert all words to upper case?

In [69]:
sentence = "Some sentence with some words"
In [70]:
[word.upper() for word in sentence.split()]
Out[70]:
['SOME', 'SENTENCE', 'WITH', 'SOME', 'WORDS']
In [71]:
[word.upper() for word in sentence.split() if word.lower().startswith("s")]
Out[71]:
['SOME', 'SENTENCE', 'SOME']
In [73]:
[i for i in range(10) if i%2==0]
Out[73]:
[0, 2, 4, 6, 8]
In [74]:
[[i*j for j in range(1, 11)] for i in range(1, 6)] # generate multiplication tables
Out[74]:
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
 [3, 6, 9, 12, 15, 18, 21, 24, 27, 30],
 [4, 8, 12, 16, 20, 24, 28, 32, 36, 40],
 [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]]

problem :

  • Write a function listpy which will list all ".py" files from given directory
    >>> listpy(os.getcwd())
    ['add.py', 'mymodule.py'...]
  • Write a function factors which will return list of factors of given number including 1 and self
    >>> factors(10)
    [1,2,5,10]

Bonus problem:

  • Given that prime number has only two factors 1 and self, write a fucntion is_prime to test primality of given number
    >>> is_prime(7)
    True
    >>> is_prime(4)
    False
  • Use above is_prime function to generate prime numbers up to n using list comprehension
  • Generate identity matrix (diagonal elements are 1, rest are zero) of 5x5 using list comprehension.
In [77]:
import os
def listpy(path):
    return [file for file in os.listdir(path) if file.endswith(".py")]
In [78]:
listpy(os.getcwd())
Out[78]:
['mymodule1.py',
 'main.py',
 'main1.py',
 'echo.py',
 'square.py',
 'mymodule.py',
 'main2.py',
 'arguments.py',
 'add.py']
In [81]:
def factors(n):
    return [i for i in range(1, n+1) if n%i == 0]
In [82]:
factors(7)
Out[82]:
[1, 7]
In [83]:
def is_prime(n):
    return factors(n) == [1,n]
In [84]:
def primes(n):
    return [p for p in range(2, n+1) if is_prime(p)]
In [95]:
primes(30)
Out[95]:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
In [96]:
[[i+j for i in range(5)] for j in range(5)]
Out[96]:
[[0, 1, 2, 3, 4],
 [1, 2, 3, 4, 5],
 [2, 3, 4, 5, 6],
 [3, 4, 5, 6, 7],
 [4, 5, 6, 7, 8]]
In [97]:
def f(x,y):
    if x==y:
        return 1
    else:
        return 0
In [98]:
[[f(i,j) for i in range(5)] for j in range(5)]
Out[98]:
[[1, 0, 0, 0, 0],
 [0, 1, 0, 0, 0],
 [0, 0, 1, 0, 0],
 [0, 0, 0, 1, 0],
 [0, 0, 0, 0, 1]]

Iteration patters

Iterating over a list, string, sequence

In [87]:
for prime in primes(30):
    print(prime)
2
3
5
7
11
13
17
19
23
29
In [88]:
for n in reversed(range(10)):
    print(n)
9
8
7
6
5
4
3
2
1
0
In [89]:
countdown = reversed([1,2,3,4,5])
In [90]:
countdown
Out[90]:
<list_reverseiterator at 0x7f9f1c656710>
In [91]:
for i in countdown:
    print(i)
5
4
3
2
1

Iterating with index

In [92]:
for i, item in enumerate(primes(23)):
    print(i, item)
0 2
1 3
2 5
3 7
4 11
5 13
6 17
7 19
8 23

Iterating with two sequences at a time

In [93]:
names = ["Elsa", "Alisa", "Exotica", "Beauty"]
surnames = ["Frozen", "Hacker", "Logica", "Nurd"]
In [94]:
for name, surname in zip(names, surnames):
    print(name, surname)
Elsa Frozen
Alisa Hacker
Exotica Logica
Beauty Nurd
In [100]:
z = zip(names, surnames)
In [101]:
z
Out[101]:
<zip at 0x7f9f1c64a8c8>
In [102]:
list(z)
Out[102]:
[('Elsa', 'Frozen'),
 ('Alisa', 'Hacker'),
 ('Exotica', 'Logica'),
 ('Beauty', 'Nurd')]

problem:

  • Write a function to do vector addition of vectors given as two lists
    >>> vector_add([1,2,3], [3,2,1])
    [4,4,4]
  • Write a function println that takes sentences as list of strings and prints each statement on new line with lines number.
    >>> s = ["This is first line", "This is second line", "This is third line", "This is last line"]
    >>> println(s)
    1 This is first line
    2 This is second line
    3 This is third line
    4 This is last line

Q: what if you pass lists of different size to zip?

In [104]:
list(zip([1,2,3], ['a','b']))
Out[104]:
[(1, 'a'), (2, 'b')]
In [105]:
list(zip([1,2,3], ['a','b','c','d']))
Out[105]:
[(1, 'a'), (2, 'b'), (3, 'c')]

Functions revisited

  • functions can be aliased
  • functions can be passed as argument to another functions
  • functions can be returned as return value from another function
In [106]:
def usual_way_polynomial(coeffs, x):
    s = 0
    for i, c in enumerate(reversed(coeffs)):
        s += c*x**i
        
    return s
In [107]:
usual_way_polynomial([1,1,1], 2) # computes x^2 + x + 1
Out[107]:
7
In [108]:
def make_adder(x):
    def adder(y):
        return x+y
    
    return adder
In [109]:
adder5 = make_adder(5)
In [110]:
adder5
Out[110]:
<function __main__.make_adder.<locals>.adder>
In [111]:
adder5(4)
Out[111]:
9
In [112]:
adder5(3)
Out[112]:
8
In [113]:
def make_plynomial(coeffs):
    def poly(x):
        s = 0
        for i, c in enumerate(reversed(coeffs)):
            s += c*x**i
        
        return s
    
    return poly
In [114]:
P2 = make_plynomial([1,1,1]) # X^2 + X + 1
In [115]:
P2
Out[115]:
<function __main__.make_plynomial.<locals>.poly>
In [116]:
P2(2)
Out[116]:
7
In [118]:
P2(3)
Out[118]:
13

problem:

  • Write a function zip_with which will take function f as argument and returns a function which zips two lists with f
In [119]:
def zip_with(f):
    def func(list1, list2):
        return [f(x,y) for x,y in zip(list1, list2)]
    
    return func
In [120]:
new_vector_add = zip_with(lambda x,y: x+y)
In [121]:
new_vector_add([1,2,3], [3,4,5])
Out[121]:
[4, 6, 8]
In [122]:
orlist = zip_with(lambda x,y: x or y)
In [123]:
orlist([True, True, False, False], [False, False, False, True])
Out[123]:
[True, True, False, True]

docstrings

In [131]:
%%file functions.py
"""
module functions
this module implements some polynomial functions

This is long description of this module
"""

def usual_way_polynomial(coeffs, x):
    """
    computes values of polynomial defined by coeffs and x
    >>> usual_way_polynomial([1,1,1], 2)
    7
    """
    s = 0
    for i, c in enumerate(reversed(coeffs)):
        s += c*x**i
        
    return s

def make_plynomial(coeffs):
    """
    makes polynomial as function given coeffs
    >>> make_plynomial([1,1,1])(2)
    7
    """
    def poly(x):
        s = 0
        for i, c in enumerate(reversed(coeffs)):
            s += c*x**i
        
        return s
    
    return poly
Overwriting functions.py
In [132]:
!pydoc functions
Help on module functions:

NNAAMMEE
    functions

DDEESSCCRRIIPPTTIIOONN
    module functions
    this module implements some polynomial functions
    
    This is long description of this module

FFUUNNCCTTIIOONNSS
    mmaakkee__ppllyynnoommiiaall(coeffs)
        makes polynomial as function given coeffs
        >>> make_plynomial([1,1,1])(2)
        7
    
    uussuuaall__wwaayy__ppoollyynnoommiiaall(coeffs, x)
        computes values of polynomial defined by coeffs and x
        >>> usual_way_polynomial([1,1,1], 2)
        7

FFIILLEE
    /home/vikrant/trainings/2017/vmware-oct-python/functions.py


Testing

In [133]:
!python -m doctest -v functions.py
Trying:
    make_plynomial([1,1,1])(2)
Expecting:
    7
ok
Trying:
    usual_way_polynomial([1,1,1], 2)
Expecting:
    7
ok
1 items had no tests:
    functions
2 items passed all tests:
   1 tests in functions.make_plynomial
   1 tests in functions.usual_way_polynomial
2 tests in 3 items.
2 passed and 0 failed.
Test passed.
In [144]:
%%file functions1.py
def add(x, y):
    return x+y


def test_add():
    if add(3,4) == 7:
        print("Pass")
    else:
        print("Failed")
        
def test_add1():
    assert add(3,4) == 7
    assert add(3,4) != 8
    assert add(0,0) == 0
    assert add(0,0) == 1
        
if __name__ == "__main__":
    test_add()
Overwriting functions1.py
In [145]:
!python functions1.py
Pass
In [146]:
!py.test functions1.py
============================= test session starts ==============================
platform linux -- Python 3.6.1, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /home/vikrant/trainings/2017/vmware-oct-python, inifile:
collected 2 items 

functions1.py .F

=================================== FAILURES ===================================
__________________________________ test_add1 ___________________________________

    def test_add1():
        assert add(3,4) == 7
        assert add(3,4) != 8
        assert add(0,0) == 0
>       assert add(0,0) == 1
E       assert 0 == 1
E        +  where 0 = add(0, 0)

functions1.py:15: AssertionError
====================== 1 failed, 1 passed in 0.06 seconds ======================

string formatting

In [147]:
def squares_and_cubes_table():
    for i in range(1,11):
        print(i, i*i, i*i*i)
In [148]:
squares_and_cubes_table()
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
In [149]:
def squares_and_cubes_table():
    for i in range(1, 11):
        print(repr(i).rjust(2), repr(i*i).rjust(3), repr(i*i*i).rjust(4))
In [150]:
squares_and_cubes_table()
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000
In [151]:
"python".rjust(10)
Out[151]:
'    python'
In [152]:
"python".ljust(10)
Out[152]:
'python    '
In [153]:
"python".center(10)
Out[153]:
'  python  '
In [154]:
"Wizard of oz is {}".format("pyhton")
Out[154]:
'Wizard of oz is pyhton'
In [155]:
"Wizard of {} is in {}".format("python", "oz")
Out[155]:
'Wizard of python is in oz'
In [159]:
"purpose of life is {1}, my computation in {0} says so!".format( "python", 0)
Out[159]:
'purpose of life is 0, my computation in python says so!'
In [160]:
"purpose of life is {purpose}, my computation in {container} says so!".format(purpose=42, container="python")
Out[160]:
'purpose of life is 42, my computation in python says so!'
In [161]:
for i in range(1, 11):
    line = "{integers:2d} {squares:3d} {cubes:4d}".format(integers=i, squares=i*i, cubes=i*i*i)
    print(line)
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000
In [163]:
"12".zfill(4)
Out[163]:
'0012'
In [164]:
"12.12".zfill(8)
Out[164]:
'00012.12'

problem:

  • Write a function to generate pascal triangle of base n
    >>> pascal(3)
    [[1],[1,1],[1,2,1]]
  • write a function print_pascal to prety print pascal triangle as shown below
    >>> print_pascal(pascal(5))
         1
        1 1
       1 2 1
      1 3 3 1
     1 4 6 4 1
In [3]:
def pascal(n):
    """
    computes pascal triangle with given base
    strategy for calulating next row is to
              1
            1   1
            \   /
              +
        1     2     1        0 1 2 1
         \   / \   /         1 2 1 0
      1    3     3     1=>  ----------
                             1 3 3 1
    """ 
    triangle = [[1]]
    
    for i in range(n-1):
        base = triangle[-1]
        l1 = base[:]
        l2 = base[:]
        l1.insert(0, 0)
        l2.append(0)
        newbase = [x+y for x,y in zip(l1, l2)]
        triangle.append(newbase)
    return triangle
In [4]:
pascal(3)
Out[4]:
[[1], [1, 1], [1, 2, 1]]
In [8]:
def print_pascal(triangle):
    def count_digits(n):
        return len(str(n))
    
    base = len(triangle[-1])
    d = count_digits(max(triangle[-1]))#number of digits in biggest number
    width = d * base + (base -1) #total width of triangle including numbers and spaces
    
    for row in triangle:
        line = ""
        for number in row:
            line += "{number:{spaces}} ".format(number=number, spaces=d)
        line = line.center(width)
        print(line)
In [9]:
print_pascal(pascal(5))
    1    
   1 1   
  1 2 1  
 1 3 3 1 
1 4 6 4 1 
In [10]:
print_pascal(pascal(15))
                                     1                                    
                                   1    1                                 
                                1    2    1                               
                              1    3    3    1                            
                           1    4    6    4    1                          
                         1    5   10   10    5    1                       
                      1    6   15   20   15    6    1                     
                    1    7   21   35   35   21    7    1                  
                 1    8   28   56   70   56   28    8    1                
               1    9   36   84  126  126   84   36    9    1             
            1   10   45  120  210  252  210  120   45   10    1           
          1   11   55  165  330  462  462  330  165   55   11    1        
       1   12   66  220  495  792  924  792  495  220   66   12    1      
     1   13   78  286  715 1287 1716 1716 1287  715  286   78   13    1   
   1   14   91  364 1001 2002 3003 3432 3003 2002 1001  364   91   14    1 
In [ ]: