Python Virtual Training For Arcesium - Module II - Nurturing Session¶

Jan 16-20, 2023 Vikrant Patil

All notes are available online at https://notes.pipal.in/2023/arcesium_finop_jan/

© Pipal Academy LLP

Write a python script tail.py which mimics unix command tail. The command will show last few lines of a file. It takes filename as argument and optional argument -n to specify how many lines to display. By default it displays last 5 lines of the file.

$ python tail.py --help
Usage: tail.py [OPTIONS] FILENAME

Arguments:
  FILENAME  [required]

Options:
  -n INTEGER                      Number of lines to display  [default: 5]
  --install-completion [bash|zsh|fish|powershell|pwsh]
                                  Install completion for the specified shell.
  --show-completion [bash|zsh|fish|powershell|pwsh]
                                  Show completion for the specified shell, to
                                  copy it or customize the installation.
  --help                          Show this message and exit.

$ python tail.py zen.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 [2]:
lines = """line1
line2
line3
line4
line5
line6""".split("\n")
In [3]:
lines
Out[3]:
['line1', 'line2', 'line3', 'line4', 'line5', 'line6']
In [7]:
def head(lines, n):
    for i, line in enumerate(lines):
        if i < n:
            print(line) # take care of \n if lines are coming from file
    
In [6]:
head(lines, 3)
line1
line2
line3
In [8]:
def head(lines, n):
    for line in lines[:n]:
        print(line) # take care of \n if lines are coming from file
    
In [9]:
head(lines, 4)
line1
line2
line3
line4
In [11]:
lines[-3::] # last three items
Out[11]:
['line4', 'line5', 'line6']
In [21]:
def tail(filename, n): 
    window = []
    with open(filename) as f:
        for i in range(n): # get first n lines
            window.append(f.readline().strip())
            
        for line in f: # go over remaining lines
            window.pop(0)
            window.append(line.strip())
            
        for line in window:
            if line: ##??? what will happen if file has lines less than n?
                print(line)
    
In [19]:
help(lines.pop)
Help on built-in function pop:

pop(index=-1, /) method of builtins.list instance
    Remove and return item at index (default last).
    
    Raises IndexError if list is empty or index is out of range.

In [20]:
tail("poem.txt", 4)
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 [30]:
%%file tail.py
import typer

def tail(filename:str, n:int=typer.Option(5, "-n", help="Number of lines")): 
    window = []
    with open(filename) as f:
        for i in range(n): # get first n lines
            window.append(f.readline().strip())
            
        for line in f: # go over remaining lines
            window.pop(0)
            window.append(line.strip())
            
        for line in window:
            if line: ##??? what will happen if file has lines less than n?
                print(line)
    
    
if __name__ == "__main__":
    typer.run(tail)
Overwriting tail.py
In [31]:
!python tail.py --help
Usage: tail.py [OPTIONS] FILENAME

Arguments:
  FILENAME  [required]

Options:
  -n INTEGER  Number of lines  [default: 5]
  --help      Show this message and exit.

print_triangle¶

Write a script print_triangle.py to print a triangle of made of character * and of base n

python print_triangle.py 5
    *
   * *
  * * *
 * * * *
* * * * *
In [34]:
def triangle(n):
    return ["*"*i for i in range(1, n+1)]
In [35]:
triangle(5)
Out[35]:
['*', '**', '***', '****', '*****']
In [36]:
"any text data".center(50)
Out[36]:
'                  any text data                   '
In [37]:
def pretty_print(triangle):
    for line in triangle:
        print(line.center(len(triangle)))
In [38]:
pretty_print(triangle(5))
  *  
  ** 
 *** 
 ****
*****
In [40]:
def pretty_print(triangle):
    n = len(triangle)
    pagewidth = n + n-1
    for line in triangle:
        l = " ".join(list(line))
        print(l.center(pagewidth))
In [41]:
pretty_print(triangle(5))
    *    
   * *   
  * * *  
 * * * * 
* * * * *
In [42]:
%%file akash_print_triangle.py
import sys

n = int(sys.argv[1])

for i in range(n):
    print(" " * (n - i - 1) + "* " * (i + 1))
Writing akash_print_triangle.py
In [43]:
!python akash_print_triangle.py 5
    * 
   * * 
  * * * 
 * * * * 
* * * * * 
In [44]:
def merge_lists(a,b):
    new_list=[]
    new_list = [item for sublist in zip(a,b) for item in sublist]
    return new_list
In [45]:
merge_lists([1, 2, 3, 4], list("abcd"))
Out[45]:
[1, 'a', 2, 'b', 3, 'c', 4, 'd']
In [46]:
a,b = [1, 2, 3, 4], list("abcd")
In [47]:
a
Out[47]:
[1, 2, 3, 4]
In [48]:
b
Out[48]:
['a', 'b', 'c', 'd']
In [50]:
[sublist for sublist in zip(a,b)]
Out[50]:
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
In [51]:
[item for sublist in zip(a,b) for item in sublist]
Out[51]:
[1, 'a', 2, 'b', 3, 'c', 4, 'd']
In [53]:
[item for item in sublist for sublist in zip(a,b)]
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[53], line 1
----> 1 [item for item in sublist for sublist in zip(a,b)]

NameError: name 'sublist' is not defined
In [54]:
import time
class Timer:
    
    def __init__(self):
        self.start_time = None
        self.end_time= None
        
    def start(self):
        self.start_time = time.time()
        
    def stop(self, n):
        time.sleep(n)
        self.end_time = time.time()
        
    def time_elapsed(self):
        print(self.end_time-self.start_time)

timer = Timer()

timer.start()

timer.stop(2)

timer.time_elapsed()
2.001695156097412
In [57]:
import time
def run_for_n_seconds(n):
    time.sleep(n)
    print("boom... done!")
In [59]:
run_for_n_seconds(5)
boom... done!
In [60]:
t = Timer()
t.start()

tail("poem.txt",5) 
run_for_n_seconds(5)
# do some more stuff

t.stop()

t.time_exapsed()
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!
boom... done!
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[60], line 8
      5 run_for_n_seconds(5)
      6 # do some more stuff
----> 8 t.stop()
     10 t.time_exapsed()

TypeError: Timer.stop() missing 1 required positional argument: 'n'

Anagram¶

In [ ]:
["eat", "ate"]
In [ ]:
"eat"  
"eta"
"aet"
"tea"


"who" w-1, h-1 o-1
"eat" e=1, a=1, t=1
"tea" e=1, a=1, t=1

"23312" ->
"22133" -> 
In [65]:
sorted("eat") # signature of an anagram!
Out[65]:
['a', 'e', 't']
In [66]:
sorted("ate")
Out[66]:
['a', 'e', 't']
In [67]:
sorted("tea")
Out[67]:
['a', 'e', 't']

SUMIFS¶

In [68]:
def SUMIFS(sum_list, criteria_list, condition):
    if condition == "": #this will never be the condition
        operator = "=="
        value = ""
    elif condition == "<>":
        operator = "!="
        value = ""
    else:
        operator = condition[:2]
        value = int(condition[2:])
    total = 0
    for i in range(len(sum_list)):
        if eval(str(criteria_list[i]) + operator + str(value)):
            total += sum_list[i]

    return total

Implement excel function SUMIFS as a function in python. SUMIFS(sum_list, criteria_list, condition). Here first argument is the list on which sum will be performed. Second argument is the list on which condition is checked, and third argument is condition as a string , as in excel.

possible values of condition are

< less than
<= less than or equal to
> greater than
>= greater than or equal to
<> not equal to
empty means equal
Sample run is shown below. For simplicity assume that all the data consists of integers.

 >>> d = [1,2,3,4,5,4,4,5]
 >>> a = [10,20,30,40,50,40,40,50]
 >>> SUMIFS(d, a, "<40")
 6
 >>> SUMIFS(d, a, ">=40")
 22
 >>> SUMIFS(d, a, "40")
 12
 >>> SUMIFS(d, a, "<>40")
 16
In [69]:
d = [1,2,3,4,5,4,4,5]
a = [10,20,30,40,50,40,40,50]
SUMIFS(d, a, "<40")
Out[69]:
6
In [73]:
SUMIFS(d, a, ">40")
Out[73]:
10
In [74]:
SUMIFS(d, a," 40")
Traceback (most recent call last):

  File ~/usr/local/default/lib/python3.10/site-packages/IPython/core/interactiveshell.py:3433 in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)

  Cell In[74], line 1
    SUMIFS(d, a," 40")

  Cell In[68], line 13 in SUMIFS
    if eval(str(criteria_list[i]) + operator + str(value)):

  File <string>:1
    10 40
       ^
SyntaxError: invalid syntax
In [79]:
import operator

def extract_num_op(condstrng):
    if condstrng.startswith("<>"):
        op = operator.ne
        num = int(condstrng[2:])
    elif condstrng.startswith("<="):
        op = operator.le
        num = int(condstrng[2:])
    elif condstrng.startswith(">="):
        op = operator.ge
        num = int(condstrng[2:])
    elif condstrng.startswith("<"):
        op = operator.lt
        num = int(condstrng[2:])
    elif condstrng.startswith(">"):
        op = operator.gt
        num = int(condstrng[2:])
    else:
        op = operator.eq
        num = int(condstrng)
    return op, num
In [82]:
def SUMIFS(sum_list, criterion_list, condstring):
    op, num = extract_num_op(condstring)
    s = 0
    for a, b in zip(sum_list, criterion_list):
        if op(b, num):
            s += a
    return s
In [84]:
SUMIFS(d, a, ">=40")
Out[84]:
22
In [85]:
SUMIFS(d, a, "40")
Out[85]:
12
In [78]:
d
Out[78]:
[1, 2, 3, 4, 5, 4, 4, 5]
In [ ]: