Basic Python Training at Grofers - Day 2

Dec 19-21, 2019 Vikrant Patil, Anand Chitipothu

These notes are available online at http://notes.pipal.in/2019/grofers_basic_dec/day2.html

© Pipal Academy LLP

Day 1 | Day 2 | Day 3

We will be using python 3 (>= 3.0) from anaconda for this training. You can download it from

https://www.anaconda.com/download/

Some Examples on lists

In [1]:
def is_palindrome(text):
    return text == text[::-1]
In [2]:
is_palindrome("madam")
Out[2]:
True
In [3]:
import os
In [4]:
os.getcwd()
Out[4]:
'/home/vikrant/trainings/2019/grofers_basic_dec'
In [6]:
os.listdir("/home/vikrant/trainings/2019/grofers_basic_dec/")
Out[6]:
['day2.html',
 'date1.py',
 'push',
 'day2.ipynb',
 'square.py',
 'day1.html',
 '__pycache__',
 'Untitled.html',
 'day3.html',
 'mysum.py',
 'Untitled.ipynb',
 'day1.ipynb',
 '.pytest_cache',
 'magic.py',
 'minimum.py',
 'square1.py',
 'date.py',
 'today.py',
 'Makefile',
 '.ipynb_checkpoints',
 'test_min.py',
 'day3.ipynb']
In [7]:
os.listdir()
Out[7]:
['day2.html',
 'date1.py',
 'push',
 'day2.ipynb',
 'square.py',
 'day1.html',
 '__pycache__',
 'Untitled.html',
 'day3.html',
 'mysum.py',
 'Untitled.ipynb',
 'day1.ipynb',
 '.pytest_cache',
 'magic.py',
 'minimum.py',
 'square1.py',
 'date.py',
 'today.py',
 'Makefile',
 '.ipynb_checkpoints',
 'test_min.py',
 'day3.ipynb']

problems

  • Write a python script ls.py which lists files in given directory
    python ls.py /home/vikrant/trainings/2019/grofers_basic_dec/
    day1.html
    day1.ipynb
    .
    .
  • Write a function squares to find squares of given list
    >>> squares([1,2,3])
    [1,4,9]
  • Write a function evens to find even numbers from given list
In [8]:
def mysum(nums):
    s = 0
    for n in nums:
        s += n
    return s
In [14]:
%%file ls.py
import os, sys

def ls(path):
    files = os.listdir(path)
    for file in files:
        print(file)

if __name__ == "__main__":
    ls(sys.argv[1])
Overwriting ls.py
In [13]:
!python ls.py .
day2.html
ls.py
date1.py
push
day2.ipynb
square.py
day1.html
__pycache__
Untitled.html
day3.html
mysum.py
Untitled.ipynb
day1.ipynb
.pytest_cache
magic.py
minimum.py
square1.py
date.py
today.py
Makefile
.ipynb_checkpoints
test_min.py
day3.ipynb
In [15]:
%%file ls1.py
import os, sys

def ls(path):
    files = os.listdir(path)
    for file in files:
        print(file)

if __name__ == "__main__":
    if len(sys.argv)==1:
        path = os.getcwd()
    else:
        path = sys.argv[1]
    ls(path)
Writing ls1.py
In [16]:
!python ls1.py 
ls1.py
day2.html
ls.py
date1.py
push
day2.ipynb
square.py
day1.html
__pycache__
Untitled.html
day3.html
mysum.py
Untitled.ipynb
day1.ipynb
.pytest_cache
magic.py
minimum.py
square1.py
date.py
today.py
Makefile
.ipynb_checkpoints
test_min.py
day3.ipynb
In [18]:
!python ls1.py "/tmp"
ssh-2y5f6AC2S1oM
.X11-unix
systemd-private-602342188a20475190f6f5bc2229a0f4-systemd-timesyncd.service-eBza1c
Temp-19e8c0b6-caf8-49eb-ba05-b23f10768176
Temp-4ed6d016-d3f1-4fdc-811a-ac3f96fba48e
systemd-private-602342188a20475190f6f5bc2229a0f4-ModemManager.service-zTq6Go
.XIM-unix
.Test-unix
.font-unix
systemd-private-602342188a20475190f6f5bc2229a0f4-rtkit-daemon.service-1ziqOs
systemd-private-602342188a20475190f6f5bc2229a0f4-colord.service-0nwbhC
.X0-lock
config-err-3zP8Kc
systemd-private-602342188a20475190f6f5bc2229a0f4-bolt.service-MN7iXA
.ICE-unix
systemd-private-602342188a20475190f6f5bc2229a0f4-systemd-resolved.service-TkFoT1
mintUpdate
In [19]:
def squares(nums):
    sqrs = []
    for n in nums:
        sqrs.append(n*n)
    return sqrs
In [20]:
def print_squares(nums):
    sqrs = squares(nums)
    print("Original list:", end=" ")
    for n in nums:
        print(n, end=" ")
        
    print("Squared list:")
    
    for s in sqrs:
        print(s, end=" ")
    
In [21]:
print_squares([2,3,4,5])
Original list: 2 3 4 5 Squared list:
4 9 16 25 
In [28]:
%%file listoperations.py

def squares(nums):
    """
    >>> squares([])
    []
    >>> squares([-1, 1, 2])
    [1, 1, 4]
    """
    sqrs = []
    for n in nums:
        sqrs.append(n*n)
    return sqrs

def evens(nums):
    def even(x):
        return x%2==0
    
    evens_ = []
    for n in nums:
        if even(n):
            evens_.append(n)
    return evens_
Overwriting listoperations.py
In [31]:
!python -m doctest -v listoperations.py
Trying:
    squares([])
Expecting:
    []
ok
Trying:
    squares([-1, 1, 2])
Expecting:
    [1, 1, 4]
ok
2 items had no tests:
    listoperations
    listoperations.evens
1 items passed all tests:
   2 tests in listoperations.squares
2 tests in 3 items.
2 passed and 0 failed.
Test passed.

problem

  • Write another module test_lists.py which writes assert tests for list_operations module and test it using pytest

List comprehensions

In [32]:
nums = [1,2,3,5,8,13]
[n*n for n in nums]
Out[32]:
[1, 4, 9, 25, 64, 169]
In [33]:
[n**3 for n in nums]
Out[33]:
[1, 8, 27, 125, 512, 2197]
In [34]:
def even(x):
    return x%2==0
[n for n in nums if even(n)]
Out[34]:
[2, 8]
In [35]:
[n*n for n in nums if even(n)]
Out[35]:
[4, 64]

Example

problem decomposition and lists comprehensions*

In [36]:
def factors(n):
    return [i for i in range(1,n+1) if n%i==0]
In [37]:
factors(12)
Out[37]:
[1, 2, 3, 4, 6, 12]
In [38]:
factors(5)
Out[38]:
[1, 5]
In [39]:
factors(7)
Out[39]:
[1, 7]
In [40]:
def is_prime(p):
    return len(factors(p))==2
In [43]:
def primes(n):
    """
    generate prime numbers less than
    """
    return [p for p in range(1, n) if is_prime(p)]
In [45]:
primes(50)
Out[45]:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

problems

  • Find sum of all multiples of 7 or 11 less than 1000
  • Write a function filterpy to filter out only py files from given directory
    >>> filterpy(path)
    a.py
    b.py
  • Write a file based on extension from given directory filter_by_ext
    filter_by_ext(path, ext)
In [47]:
4==3 or 4%2==0 and 1==1
Out[47]:
True
In [48]:
sum([1,2,3,4])
Out[48]:
10
e = []
for i in range(n):
    e.append(do(i))

Above loop translates to list comprehesnion as below

[do(i) for i in range(n)]

=======================================================

e = []
for i in range(n):
    if cond(i):
        e.append(do(i))

Above loop translates to list comprehesnion as below

[do(i) for i in range(n) if cond(i)]
In [49]:
sum([i for i in range(1,1000) if i%7==0 or i%11==0])
Out[49]:
110110
In [50]:
def filter_py(path):
    files = os.listdir(path)
    return [file for file in files if file.endswith(".py")]

def filter_by_ext(path, ext):
    files = os.listdir(path)
    return [file for file in files if file.endswith(ext)]

def filter_py1(path):
    return filter_by_ext(path, ".py")
In [1]:
tables = [[i*j for i in range(1,6)] for j in range(1,11)]
In [2]:
tables
Out[2]:
[[1, 2, 3, 4, 5],
 [2, 4, 6, 8, 10],
 [3, 6, 9, 12, 15],
 [4, 8, 12, 16, 20],
 [5, 10, 15, 20, 25],
 [6, 12, 18, 24, 30],
 [7, 14, 21, 28, 35],
 [8, 16, 24, 32, 40],
 [9, 18, 27, 36, 45],
 [10, 20, 30, 40, 50]]
In [3]:
tables[0]
Out[3]:
[1, 2, 3, 4, 5]
In [4]:
tables[-1]
Out[4]:
[10, 20, 30, 40, 50]
In [5]:
tables[:]
Out[5]:
[[1, 2, 3, 4, 5],
 [2, 4, 6, 8, 10],
 [3, 6, 9, 12, 15],
 [4, 8, 12, 16, 20],
 [5, 10, 15, 20, 25],
 [6, 12, 18, 24, 30],
 [7, 14, 21, 28, 35],
 [8, 16, 24, 32, 40],
 [9, 18, 27, 36, 45],
 [10, 20, 30, 40, 50]]
In [6]:
tables[2:]
Out[6]:
[[3, 6, 9, 12, 15],
 [4, 8, 12, 16, 20],
 [5, 10, 15, 20, 25],
 [6, 12, 18, 24, 30],
 [7, 14, 21, 28, 35],
 [8, 16, 24, 32, 40],
 [9, 18, 27, 36, 45],
 [10, 20, 30, 40, 50]]
In [7]:
tables[0]
Out[7]:
[1, 2, 3, 4, 5]
In [8]:
tables[0][2]
Out[8]:
3
In [9]:
tables[1][2]
Out[9]:
6
In [10]:
tables[2][2]
Out[10]:
9
In [11]:
def column(data, colnum):
    return [data[i][colnum] for i in range(len(data))]
In [12]:
column(tables, 2)
Out[12]:
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
In [13]:
tables
Out[13]:
[[1, 2, 3, 4, 5],
 [2, 4, 6, 8, 10],
 [3, 6, 9, 12, 15],
 [4, 8, 12, 16, 20],
 [5, 10, 15, 20, 25],
 [6, 12, 18, 24, 30],
 [7, 14, 21, 28, 35],
 [8, 16, 24, 32, 40],
 [9, 18, 27, 36, 45],
 [10, 20, 30, 40, 50]]
In [15]:
def transpose(data):
    colcount = len(data[0])
    return [column(data, c) for c in range(colcount)]
In [17]:
transpose(tables)
Out[17]:
[[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]]

Iteration Patterns

In [18]:
nums = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
In [19]:
for n in nums:
    print(n, end=",")
2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,
In [20]:
for i, n in enumerate(nums[:5]):
    print(i, n)
0 2
1 3
2 5
3 7
4 11
In [23]:
lines = """first line
second line
third line
fourth line
""".strip().split("\n")
In [24]:
lines
Out[24]:
['first line', 'second line', 'third line', 'fourth line']
In [25]:
for linum, line in enumerate(lines, start=1):
    print(linum, line)
1 first line
2 second line
3 third line
4 fourth line
In [26]:
x, y = 1,2
In [27]:
enumerate(lines)
Out[27]:
<enumerate at 0x7f118d3bf120>
In [28]:
list(enumerate(lines))
Out[28]:
[(0, 'first line'), (1, 'second line'), (2, 'third line'), (3, 'fourth line')]
In [29]:
list(enumerate(lines, start=1))
Out[29]:
[(1, 'first line'), (2, 'second line'), (3, 'third line'), (4, 'fourth line')]
In [30]:
for line in reversed(lines):
    print(line)
fourth line
third line
second line
first line
In [31]:
for i in reversed(range(5)):
    print(i)
4
3
2
1
0
In [32]:
first = ["Elsa", "Alice", "Elisa"]
second = ["Frozen", "Wonder", "Hacker"]
for f, s in zip(first, second):
    print(f, s)
Elsa Frozen
Alice Wonder
Elisa Hacker
In [33]:
a = [1, 2, 3, 4]
b = ['a','b','c']
for i, j in zip(a,b):
    print(i,j)
1 a
2 b
3 c
In [34]:
items = ["Daliya", "Rava", "Rice"]
quantities = [2,1,3]
prices = [32, 40, 50]
for item, qty,price in zip(items, quantities, prices):
    print(item, qty, price)
Daliya 2 32
Rava 1 40
Rice 3 50
In [35]:
items = ["Daliya", "Rava", "Rice"]
quantities = [2,1,3]
prices = [32, 40, 50]
for item, qty,price in zip(items, quantities, prices):
    print(item.rjust(6), qty, price)
Daliya 2 32
  Rava 1 40
  Rice 3 50
In [36]:
r = reversed([1, 2, 3, 4]) # is only for one time use!
In [37]:
for i in r:
    print(i, end=" ")
4 3 2 1 
In [39]:
for i in r:# is only for one time use!
    print(i, end=" ")

problems

  • Write a function to vector add two lists
    >>> vector_add([1, 2, 3], [1, 1, 1])
    [2, 3, 4]
In [40]:
def vector_add(vector1, vector2):
    return [a+b for a,b in zip(vector1, vector2)]
In [41]:
vector_add([2, 3, 4, 5], [1, 1, 1, 1])
Out[41]:
[3, 4, 5, 6]

String formating

In [42]:
for i in range(1, 11):
    print(i, i**2, i**3)
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 [43]:
for i in range(1, 11):
    print(str(i).rjust(2), str(i**2).rjust(3), str(i**3).rjust(4))
 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 [44]:
"Answer to {} is {}".format("life", 42)
Out[44]:
'Answer to life is 42'
In [45]:
"Answer to {1} is {0}".format("life", 42)
Out[45]:
'Answer to 42 is life'
In [46]:
"Wizard of {place} is {name}".format(place="oz", name="python")
Out[46]:
'Wizard of oz is python'
In [47]:
template = """
<html>
<header>
{HEADER}
</header>
<body>
{BODY}
</body>
</html>
"""
In [49]:
print(template.format(HEADER="Post1", BODY="Contests of Post1"))
<html>
<header>
Post1
</header>
<body>
Contests of Post1
</body>
</html>

In [50]:
for i in range(1, 11):
    print("{num:2} {sqr:3} {cube:4}".format(num=i, sqr=i*i, cube=i**3))
 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 [51]:
for i in range(1, 11):
    print("{num:{w}} {sqr:{w}} {cube:{w}}".format(num=i, sqr=i*i, cube=i**3, w=4))
   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 [52]:
def make_triangle(n):
    return ["*"*row for row in range(1, n+1)]
In [53]:
make_triangle(5)
Out[53]:
['*', '**', '***', '****', '*****']
In [54]:
for row in make_triangle(5):
    print(row)
*
**
***
****
*****
In [55]:
"helo".center(10)
Out[55]:
'   helo   '
In [56]:
def prety_print(triangle):
    width = len(triangle[-1])
    for row in triangle:
        print(row.center(width))
In [58]:
prety_print(make_triangle(10))
    *     
    **    
   ***    
   ****   
  *****   
  ******  
 *******  
 ******** 
********* 
**********
In [59]:
def format_row(row):
    return " ".join(list(row))

def prety_print(triangle):
    base = len(triangle[-1])
    width = base + base -1
    for row in triangle:
        row_ = format_row(row)
        print(row_.center(width))
In [60]:
prety_print(make_triangle(10))
         *         
        * *        
       * * *       
      * * * *      
     * * * * *     
    * * * * * *    
   * * * * * * *   
  * * * * * * * *  
 * * * * * * * * * 
* * * * * * * * * *
In [61]:
def make_triangle(n, char="*"):
    return [char*row for row in range(1, n+1)]
In [63]:
make_triangle(10, "@")
Out[63]:
['@',
 '@@',
 '@@@',
 '@@@@',
 '@@@@@',
 '@@@@@@',
 '@@@@@@@',
 '@@@@@@@@',
 '@@@@@@@@@',
 '@@@@@@@@@@']
In [64]:
prety_print(make_triangle(10, "@"))
         @         
        @ @        
       @ @ @       
      @ @ @ @      
     @ @ @ @ @     
    @ @ @ @ @ @    
   @ @ @ @ @ @ @   
  @ @ @ @ @ @ @ @  
 @ @ @ @ @ @ @ @ @ 
@ @ @ @ @ @ @ @ @ @

problem

  • Write a function to generate pascal triangle of base n
    >>> pascal(4)
    [[1],[1,1],[1,2,1],[1,3,3,1]]
In [65]:
11**4
Out[65]:
14641
In [66]:
11**5
Out[66]:
161051
In [72]:
%%file pascal.py

def get_next_row(row):
    r1 = [0] + row[:]
    r2 = row[:] + [0]
    return [a+b for a,b in zip(r1, r2)]

def test_get_next_row():
    assert get_next_row([1]) == [1,1]
    assert get_next_row([1,1]) == [1,2,1]
    assert get_next_row(get_next_row([1])) == [1,2,1]
Overwriting pascal.py
In [71]:
!pytest pascal.py
============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/vikrant/trainings/2019/grofers_basic_dec
plugins: doctestplus-0.3.0, benchmark-3.2.2, cov-2.8.1, arraydiff-0.3, remotedata-0.3.1, openfiles-0.3.2
collected 1 item                                                               

pascal.py .                                                              [100%]

=========================== 1 passed in 0.03 seconds ===========================
In [73]:
%%file pascal1.py

def pascal(n):
    tr = [[1]]
    for i in range(n-1):
        last = tr[-1]
        tr.append(get_next_row(last))
    return tr

def test_pascal():
    assert pascal(1) == [[1]]
    assert pascal(2) == [[1],[1,1]]
    assert pascal(3) == [[1],[1,1],[1,2,1]]
    
def get_next_row(row):
    r1 = [0] + row[:]
    r2 = row[:] + [0]
    return [a+b for a,b in zip(r1, r2)]

def test_get_next_row():
    assert get_next_row([1]) == [1,1]
    assert get_next_row([1,1]) == [1,2,1]
    assert get_next_row(get_next_row([1])) == [1,2,1]
Writing pascal1.py
In [74]:
!pytest pascal1.py
============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/vikrant/trainings/2019/grofers_basic_dec
plugins: doctestplus-0.3.0, benchmark-3.2.2, cov-2.8.1, arraydiff-0.3, remotedata-0.3.1, openfiles-0.3.2
collected 2 items                                                              

pascal1.py ..                                                            [100%]

=========================== 2 passed in 0.03 seconds ===========================
In [76]:
from pascal1 import pascal
In [78]:
pascal(5)
Out[78]:
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]
In [93]:
def print_pascal(n):
    pascal_t = pascal(n)
    
    def format_row(row, boxwidth):
        return " ".join([f"{r:{boxwidth}}" for r in row])
    
    maxnum = max(pascal_t[-1])
    boxwidth = len(str(maxnum))
    length = len(pascal_t[-1])
    width = boxwidth*length + length -1
    for row in pascal_t:
        row_ = format_row(row, boxwidth)
        print(row_.center(width))
In [94]:
print_pascal(5)
    1    
   1 1   
  1 2 1  
 1 3 3 1 
1 4 6 4 1
In [97]:
print_pascal(12)
                        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

Working with files

In [98]:
import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
In [99]:
%%file poem.txt
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Writing poem.txt
In [100]:
with open("poem.txt") as file:
    print(file.read())
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

In [102]:
with open("poem.txt") as file:
    for line in file:
        print(line)
The Zen of Python, by Tim Peters



Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

Special cases aren't special enough to break the rules.

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

In the face of ambiguity, refuse the temptation to guess.

There should be one-- and preferably only one --obvious way to do it.

Although that way may not be obvious at first unless you're Dutch.

Now is better than never.

Although never is often better than *right* now.

If the implementation is hard to explain, it's a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea -- let's do more of those!

In [104]:
with open("poem.txt") as file: # with statement makes sure that file 
    for line in file:          # is closed after with block
        print(line, end="")
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
In [105]:
file = open("poem.txt")
In [106]:
file.readline()
Out[106]:
'The Zen of Python, by Tim Peters\n'
In [107]:
file.readline()
Out[107]:
'\n'
In [108]:
file.read()
Out[108]:
"Beautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\nComplex is better than complicated.\nFlat is better than nested.\nSparse is better than dense.\nReadability counts.\nSpecial cases aren't special enough to break the rules.\nAlthough practicality beats purity.\nErrors should never pass silently.\nUnless explicitly silenced.\nIn the face of ambiguity, refuse the temptation to guess.\nThere should be one-- and preferably only one --obvious way to do it.\nAlthough that way may not be obvious at first unless you're Dutch.\nNow is better than never.\nAlthough never is often better than *right* now.\nIf the implementation is hard to explain, it's a bad idea.\nIf the implementation is easy to explain, it may be a good idea.\nNamespaces are one honking great idea -- let's do more of those!\n"
In [109]:
file.read()
Out[109]:
''
In [110]:
file.readline()
Out[110]:
''
In [111]:
file.close()
In [112]:
with open("poem.txt") as f:
    line = f.readline()
    while line:
        print(line, end="")
        line = f.readline()
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
In [114]:
if '':
    print("false")
else:
    print("True")
True
In [115]:
%%file small.txt
one
two
three
Writing small.txt
In [116]:
f = open("small.txt")
In [117]:
f.readline()
Out[117]:
'one\n'
In [118]:
f.readline()
Out[118]:
'two\n'
In [119]:
f.readline()
Out[119]:
'three\n'
In [120]:
f.readline()
Out[120]:
''
In [121]:
f.close()
In [122]:
with open("small.txt") as f:
    while f.readline():
        pass
In [124]:
with open("small.txt") as f:
    for line in f:
        print(line, end="")
one
two
three

problems

  • Write a function to print file with line numbers
  • Write a function revered_lines to print every line in reversed fashion
    >>> reversed_line("small.txt")
    eno
    owt
    eerht
  • Write python script cat.py which mimics unix command cat
  • Write a python script head.py which mimics unix command head
  • Make use of list to write a python script tail.py which prints last five lines of a file.
In [126]:
!head -n 5 poem.txt
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
In [127]:
!tail -n 5 poem.txt
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
In [128]:
def lines_nums(filename):
    with open(filename) as f:
        for linum, line in enumerate(f, start=1):
            print(linum, line, end="")
In [129]:
lines_nums("poem.txt")
1 The Zen of Python, by Tim Peters
2 
3 Beautiful is better than ugly.
4 Explicit is better than implicit.
5 Simple is better than complex.
6 Complex is better than complicated.
7 Flat is better than nested.
8 Sparse is better than dense.
9 Readability counts.
10 Special cases aren't special enough to break the rules.
11 Although practicality beats purity.
12 Errors should never pass silently.
13 Unless explicitly silenced.
14 In the face of ambiguity, refuse the temptation to guess.
15 There should be one-- and preferably only one --obvious way to do it.
16 Although that way may not be obvious at first unless you're Dutch.
17 Now is better than never.
18 Although never is often better than *right* now.
19 If the implementation is hard to explain, it's a bad idea.
20 If the implementation is easy to explain, it may be a good idea.
21 Namespaces are one honking great idea -- let's do more of those!
In [130]:
def reversed_lines(filename):
    with open(filename) as f:
        for line in f:
            print(line.strip()[::-1])
In [131]:
reversed_lines("poem.txt")
sreteP miT yb ,nohtyP fo neZ ehT

.ylgu naht retteb si lufituaeB
.ticilpmi naht retteb si ticilpxE
.xelpmoc naht retteb si elpmiS
.detacilpmoc naht retteb si xelpmoC
.detsen naht retteb si talF
.esned naht retteb si esrapS
.stnuoc ytilibadaeR
.selur eht kaerb ot hguone laiceps t'nera sesac laicepS
.ytirup staeb ytilacitcarp hguohtlA
.yltnelis ssap reven dluohs srorrE
.decnelis ylticilpxe sselnU
.sseug ot noitatpmet eht esufer ,ytiugibma fo ecaf eht nI
.ti od ot yaw suoivbo-- eno ylno ylbareferp dna --eno eb dluohs erehT
.hctuD er'uoy sselnu tsrif ta suoivbo eb ton yam yaw taht hguohtlA
.reven naht retteb si woN
.won *thgir* naht retteb netfo si reven hguohtlA
.aedi dab a s'ti ,nialpxe ot drah si noitatnemelpmi eht fI
.aedi doog a eb yam ti ,nialpxe ot ysae si noitatnemelpmi eht fI
!esoht fo erom od s'tel -- aedi taerg gniknoh eno era secapsemaN
In [132]:
with open("poem.txt") as f:
    lines = f.readlines()
    for line in lines:
        print(line.strip()[::-1])
sreteP miT yb ,nohtyP fo neZ ehT

.ylgu naht retteb si lufituaeB
.ticilpmi naht retteb si ticilpxE
.xelpmoc naht retteb si elpmiS
.detacilpmoc naht retteb si xelpmoC
.detsen naht retteb si talF
.esned naht retteb si esrapS
.stnuoc ytilibadaeR
.selur eht kaerb ot hguone laiceps t'nera sesac laicepS
.ytirup staeb ytilacitcarp hguohtlA
.yltnelis ssap reven dluohs srorrE
.decnelis ylticilpxe sselnU
.sseug ot noitatpmet eht esufer ,ytiugibma fo ecaf eht nI
.ti od ot yaw suoivbo-- eno ylno ylbareferp dna --eno eb dluohs erehT
.hctuD er'uoy sselnu tsrif ta suoivbo eb ton yam yaw taht hguohtlA
.reven naht retteb si woN
.won *thgir* naht retteb netfo si reven hguohtlA
.aedi dab a s'ti ,nialpxe ot drah si noitatnemelpmi eht fI
.aedi doog a eb yam ti ,nialpxe ot ysae si noitatnemelpmi eht fI
!esoht fo erom od s'tel -- aedi taerg gniknoh eno era secapsemaN
In [133]:
%%file cat.py
import sys

def cat(filename):
    with open(filename) as f:
        print(f.read())
        
if __name__ == "__main__":
    cat(sys.argv[1])
Writing cat.py
In [134]:
!python cat.py poem.txt
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

In [135]:
!cat small.txt poem.txt
one
two
three
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
In [136]:
%%file cat.py
import sys

def cat_(files):
    for file in files:
        cat(file)

def cat(filename):
    with open(filename) as f:
        print(f.read())
        
if __name__ == "__main__":
    cat_(sys.argv[1:])
Overwriting cat.py
In [137]:
!python cat.py small.txt poem.txt
one
two
three

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

In [138]:
!python cat.py small.txt
one
two
three

In [141]:
%%file head.py

import sys

def head(n, filename):
    with open(filename) as f:
        for i in range(n):
            print(f.readline(), end="")
            
if __name__ == "__main__":
    head(int(sys.argv[1]), sys.argv[2])
Overwriting head.py
In [142]:
!python head.py 3 poem.txt
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
In [144]:
nums[-5:]
Out[144]:
[31, 37, 41, 43, 47]
In [145]:
nums
Out[145]:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
In [153]:
def tail(filename, n):
    window = []
    with open(filename) as f:
        for i in range(n):
            window.append(f.readline())
        line = f.readline()
        while line:
            window.pop(0)
            window.append(line)
            line = f.readline()
            
    for l in window:
        print(l, end="")
    
In [154]:
tail("poem.txt", 5)
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

more about testing

In [155]:
!pytest pascal1.py
============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/vikrant/trainings/2019/grofers_basic_dec
plugins: doctestplus-0.3.0, benchmark-3.2.2, cov-2.8.1, arraydiff-0.3, remotedata-0.3.1, openfiles-0.3.2
collected 2 items                                                              

pascal1.py ..                                                            [100%]

=========================== 2 passed in 0.01 seconds ===========================
In [159]:
!pip install pytest-cov pytest-benchmark
Usage:   
  pip install [options] <requirement specifier> [package-index-options] ...
  pip install [options] -r <requirements file> [package-index-options] ...
  pip install [options] [-e] <vcs project url> ...
  pip install [options] [-e] <local project path> ...
  pip install [options] <archive url/path> ...

no such option: --capture
In [167]:
!pytest --capture=no --cov=.
============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/vikrant/trainings/2019/grofers_basic_dec
plugins: doctestplus-0.3.0, benchmark-3.2.2, cov-2.8.1, arraydiff-0.3, remotedata-0.3.1, openfiles-0.3.2
collected 2 items                                                              

test_min.py .F

=================================== FAILURES ===================================
__________________________________ test_min3 ___________________________________

    def test_min3():
        assert minimum.min3(1, 2, 3)==1
        assert minimum.min3(1,1, 1)==1
>       assert minimum.min3(2,1, -1)==1
E       assert -1 == 1
E        +  where -1 = <function min3 at 0x7f7523ba0a60>(2, 1, -1)
E        +    where <function min3 at 0x7f7523ba0a60> = minimum.min3

test_min.py:11: AssertionError

----------- coverage: platform linux, python 3.7.3-final-0 -----------
Name                Stmts   Miss  Cover
---------------------------------------
cat.py                  9      9     0%
date.py                 3      3     0%
date1.py                4      4     0%
head.py                 7      7     0%
listoperations.py      13     13     0%
ls.py                   7      7     0%
ls1.py                 10     10     0%
magic.py                1      1     0%
minimum.py              8      1    88%
mysum.py                8      8     0%
pascal.py               8      8     0%
pascal1.py             18     18     0%
square.py               7      7     0%
square1.py              6      6     0%
test_min.py             9      0   100%
today.py                5      5     0%
---------------------------------------
TOTAL                 123    107    13%

====================== 1 failed, 1 passed in 0.09 seconds ======================
In [162]:
 
============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/vikrant/trainings/2019/grofers_basic_dec
plugins: doctestplus-0.3.0, benchmark-3.2.2, cov-2.8.1, arraydiff-0.3, remotedata-0.3.1, openfiles-0.3.2
collected 2 items                                                              

test_min.py .FCoverage.py warning: Module pascal1.py was never imported. (module-not-imported)
Coverage.py warning: No data was collected. (no-data-collected)
WARNING: Failed to generate report: No data to report.

/home/vikrant/anaconda3/lib/python3.7/site-packages/pytest_cov/plugin.py:254: PytestWarning: Failed to generate report: No data to report.

  self.cov_controller.finish()


=================================== FAILURES ===================================
__________________________________ test_min3 ___________________________________

    def test_min3():
        assert minimum.min3(1, 2, 3)==1
        assert minimum.min3(1,1, 1)==1
>       assert minimum.min3(2,1, -1)==1
E       assert -1 == 1
E        +  where -1 = <function min3 at 0x7f9066dbea60>(2, 1, -1)
E        +    where <function min3 at 0x7f9066dbea60> = minimum.min3

test_min.py:11: AssertionError

----------- coverage: platform linux, python 3.7.3-final-0 -----------

====================== 1 failed, 1 passed in 0.05 seconds ======================

benchmarking

Example

Write a function to find unique items from a list, while keeping the order

In [171]:
%%file unique.py

def unique(seq):
    seen = []
    u  = []
    for item in seq:
        if item not in seen:
            u.append(item)
            seen.append(item)
    return u

def unique1(seq):
    seen = set()
    u = []
    for item in seq:
        if item not in seen:
            u.append(item)
            seen.add(item)
    return u

def test_bechmark_unique(benchmark):
    benchmark(unique, range(10000))

def test_bechmark_unique1(benchmark):
    benchmark(unique1, range(10000))
    
Overwriting unique.py
In [173]:
!pytest -vv unique.py
============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 -- /home/vikrant/anaconda3/bin/python
cachedir: .pytest_cache
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/vikrant/trainings/2019/grofers_basic_dec
plugins: doctestplus-0.3.0, benchmark-3.2.2, cov-2.8.1, arraydiff-0.3, remotedata-0.3.1, openfiles-0.3.2
collected 2 items                                                              

unique.py::test_bechmark_unique PASSED                                   [ 50%]
unique.py::test_bechmark_unique1 PASSED                                  [100%]


-------------------------------------------------------------------------------------- benchmark: 2 tests --------------------------------------------------------------------------------------
Name (time in ms)              Min                 Max                Mean             StdDev              Median                IQR            Outliers       OPS            Rounds  Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_bechmark_unique1       1.2249 (1.0)        3.5156 (1.0)        1.2437 (1.0)       0.1008 (1.0)        1.2356 (1.0)       0.0055 (1.0)          7;39  804.0710 (1.0)         715           1
test_bechmark_unique      523.0453 (427.02)   570.8395 (162.37)   533.3227 (428.83)   20.9999 (208.33)   523.5422 (423.71)   13.7183 (>1000.0)       1;1    1.8750 (0.00)          5           1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
=========================== 2 passed in 5.67 seconds ===========================

test fixtures

In [178]:
%%file words.py
def get_words(file):
    with open(file) as f:
        return f.read().strip().split()
Writing words.py
In [191]:
%%file test_words.py
import pytest
from words import get_words
import os

@pytest.fixture
def wordfile():
    path = "/tmp/wordcounttest.txt"
    with open(path, "w") as f:
        f.write("one two three")
    print("Setup.....")

    yield path
    
    print("Teardown...")
    os.remove(path)
    
def test_words(wordfile):
    print("[Test]:", wordfile)
    assert get_words(wordfile)==["one","two","three"]
    
Overwriting test_words.py
In [192]:
!pytest -vv --capture=no test_words.py
============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 -- /home/vikrant/anaconda3/bin/python
cachedir: .pytest_cache
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/vikrant/trainings/2019/grofers_basic_dec
plugins: doctestplus-0.3.0, benchmark-3.2.2, cov-2.8.1, arraydiff-0.3, remotedata-0.3.1, openfiles-0.3.2
collected 1 item                                                               

test_words.py::test_words Setup.....
[Test]: /tmp/wordcounttest.txt
PASSEDTeardown...


=========================== 1 passed in 0.02 seconds ===========================

Working with dictinaries

In [194]:
person = {"name":"Vikrant",
          "email":"vikrant@pipalacademy", 
          "address":"Pune"}
In [195]:
person['name']
Out[195]:
'Vikrant'
In [196]:
person['company']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-196-a2b0e6ec2841> in <module>
----> 1 person['company']

KeyError: 'company'
In [197]:
person.get("company", "Pipal Academy")
Out[197]:
'Pipal Academy'
In [198]:
person
Out[198]:
{'name': 'Vikrant', 'email': 'vikrant@pipalacademy', 'address': 'Pune'}
In [199]:
person.get("company")
In [200]:
print(person.get("company"))
None
In [201]:
for key in person:
    print(key)
name
email
address
In [202]:
for key in person:
    print(key, person[key])
name Vikrant
email vikrant@pipalacademy
address Pune
In [203]:
for value in person.values():
    print(value)
Vikrant
vikrant@pipalacademy
Pune
In [204]:
for key, value in person.items():
    print(key, value)
name Vikrant
email vikrant@pipalacademy
address Pune
In [205]:
%%file words.txt
one
one two 
one two three
one two three four
one two three four five
one two three four six
one two three six seven
one two six seven eight
one six seven eight nine
six seven eight nine ten
seven eight nine ten
eight nine ten
nine ten
ten
Writing words.txt
In [206]:
def get_words(filename):
    with open(filename) as f:
        return f.read().strip().split()
In [207]:
def wordfreq(words):
    freq = {}
    for w in words:
        if w not in freq:
            freq[w] = 1
        else:
            freq[w] +=1
    return freq
    
In [208]:
def wordfreq1(words):
    freq = {}
    for w in words:
        freq[w] = freq.get(w, 0) + 1
    return freq
    
In [209]:
def wordfreq2(words):
    uniq = set(words)
    for w in uniq:
        freq[w] = words.count(w)
    return freq
    
In [210]:
words = get_words("words.txt")
In [212]:
freq = wordfreq1(words)
In [213]:
freq
Out[213]:
{'one': 9,
 'two': 7,
 'three': 5,
 'four': 3,
 'five': 1,
 'six': 5,
 'seven': 5,
 'eight': 5,
 'nine': 5,
 'ten': 5}
In [214]:
for word in sorted(freq,key=lambda w: freq[w]):
    print(word, freq[word])
five 1
four 3
three 5
six 5
seven 5
eight 5
nine 5
ten 5
two 7
one 9
In [216]:
def get_freq(w):
    return freq[w]

for word in sorted(freq,key=get_freq, reverse=True):
    print(word, freq[word])
one 9
two 7
three 5
six 5
seven 5
eight 5
nine 5
ten 5
four 3
five 1
In [217]:
for word, f in sorted(freq.items(),key=lambda r: r[1], reverse=True):
    print(word, freq[word])
one 9
two 7
three 5
six 5
seven 5
eight 5
nine 5
ten 5
four 3
five 1
In [218]:
for word, f in sorted(freq.items(),key=lambda r: r[1], reverse=True):
    print(word.rjust(5), f, "*"*f)
  one 9 *********
  two 7 *******
three 5 *****
  six 5 *****
seven 5 *****
eight 5 *****
 nine 5 *****
  ten 5 *****
 four 3 ***
 five 1 *

testing untestable!

In [221]:
%%file weekday.py

import datetime

def now():
    return datetime.datetime.now()

def weekday():
    t = now()
    return t.strftime("%A")

if __name__ == "__main__":
    print(weekday())
Overwriting weekday.py
In [222]:
!python weekday.py
Friday
In [225]:
%%file test_weekday.py
import weekday
import datetime

def test_weekday(monkeypatch):
    faketime = 2010, 1, 1
    def fakenow():
        return datetime.datetime(*faketime)
    
    monkeypatch.setattr(weekday, "now", fakenow)
    
    faketime = 2010, 1, 1
    assert weekday.weekday() == "Friday"
    
    faketime = 2010, 1, 2
    assert weekday.weekday() == "Saturday"
Overwriting test_weekday.py
In [226]:
!pytest test_weekday.py
============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/vikrant/trainings/2019/grofers_basic_dec
plugins: doctestplus-0.3.0, benchmark-3.2.2, cov-2.8.1, arraydiff-0.3, remotedata-0.3.1, openfiles-0.3.2
collected 1 item                                                               

test_weekday.py .                                                        [100%]

=========================== 1 passed in 0.03 seconds ===========================
In [ ]: