Basic Python Training at Arcesium - Day 2

Sep 23-24, 2019 Vikrant Patil

These notes are available online at http://notes.pipal.in/2019/arcesium_basic_sep/day1.html

© Pipal Academy LLP

Day 1 | Day 2

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

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

bonus problems

  • Write a list comprehension to generate 5x5 unit matrix. a unit matrix is a matrix with diagonal element as 1 evry other element is 0
  • Write an expression to sum all multiples of 7 or 11 less than 1000
  • Write a function to rodate 2D list 90 degrees clockwise
  • Write a function to find sum of digits of given integer
    >>> sumdigits(1111)
    4
In [7]:
d = {True:1, False:0}
I = [[d[i==j] for i in range(5)] for j in range(5)]
I
Out[7]:
[[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]]
In [2]:
sum([i for i in range(1000) if i%7==0 or i%11==0])
Out[2]:
110110
In [9]:
def column(data, c):
    return [data[r][c] for r in range(len(data))]

def reversedcolumn(data, c):
    return [data[r][c] for r in reversed(range(len(data)))]
In [10]:
def rotate90(data):
    colcount = len(data[0])
    return [reversedcolumn(data, c) for c in range(colcount)]
In [11]:
rotate90(I)
Out[11]:
[[0, 0, 0, 0, 1],
 [0, 0, 0, 1, 0],
 [0, 0, 1, 0, 0],
 [0, 1, 0, 0, 0],
 [1, 0, 0, 0, 0]]
In [12]:
print(__name__)
__main__

Sring formating

In [13]:
for i in range(1, 11):
    print(i, i*i, 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 [14]:
for i in range(1, 11):
    print(str(i).rjust(2), str(i*i).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 [16]:
w = 4
for i in range(1, 11):
    print(str(i).rjust(w), str(i*i).rjust(w), str(i**3).rjust(w))
   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 [17]:
htmltemplate ="""
<html>
<header>
{HEADER}
</header
<body>
<p>
{CONTENTS}
</p>
</body>
</html>
"""
In [18]:
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 [19]:
poem = """
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 [20]:
html = htmltemplate.format(HEADER="Zen of Python", CONTENTS=poem)
In [21]:
print(html)
<html>
<header>
Zen of Python
</header
<body>
<p>

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!

</p>
</body>
</html>

In [23]:
"{} of oz is {}".format("Wizard", "Python")
Out[23]:
'Wizard of oz is Python'
In [24]:
"{1} of oz is {0}".format("Wizard", "Python")
Out[24]:
'Python of oz is Wizard'
In [25]:
"{wizard} of oz is {somebody}".format(wizard="Wizard", somebody="Python")
Out[25]:
'Wizard of oz is Python'
In [26]:
import jason
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-26-c45ff7b12c06> in <module>
----> 1 import jason

ModuleNotFoundError: No module named 'jason'
In [27]:
import json
In [28]:
json.dumps(I)
Out[28]:
'[[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]]'
In [30]:
d = {"data":I, "attr1":"hello"}
In [31]:
d
Out[31]:
{'data': [[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]],
 'attr1': 'hello'}
In [33]:
jsonstring = json.dumps(d)
In [34]:
jsonstring
Out[34]:
'{"data": [[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]], "attr1": "hello"}'
In [35]:
json.loads(jsonstring)
Out[35]:
{'data': [[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]],
 'attr1': 'hello'}

problems

  • Write a function to generate pascal triangle
    >>> pascal(4)
    [[1],[1,1],[1,2,1],[1,3,3,1]]
  • Write a function to pretty print a triangle of *
                    *
                   * *
                  * * *
                 * * * *
                * * * * *

bonus

  • Write a function to pretty print pascal trianlge
In [36]:
r = [1, 2, 1]
In [37]:
r1 = r[:]
r2 = r[:]
In [38]:
r1
Out[38]:
[1, 2, 1]
In [39]:
r2
Out[39]:
[1, 2, 1]
In [40]:
r1.append(0)
r2.insert(0, 0)
In [41]:
r1
Out[41]:
[1, 2, 1, 0]
In [42]:
r2
Out[42]:
[0, 1, 2, 1]
In [43]:
[i+j for i,j in zip(r1, r2)]
    
Out[43]:
[1, 3, 3, 1]
In [44]:
def nextrow(r):
    r1 = r[:]
    r2 = r[:]
    r1 = r1 + [0]
    r2 = [0] + r2
    return [x+y for x,y in zip(r1, r2)]
In [45]:
nextrow([1])
Out[45]:
[1, 1]
In [46]:
def pascal(n):
    t = [[1]]
    for i in range(n-1):
        prev = t[-1]
        nextr = nextrow(prev)
        t.append(nextr)
    return t
In [47]:
pascal(5)
Out[47]:
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]
In [48]:
pascal(6)
Out[48]:
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]
In [49]:
"*"*5
Out[49]:
'*****'
In [50]:
["*"]*5
Out[50]:
['*', '*', '*', '*', '*']
In [51]:
def triangle(base, char="*"):
    return [ [char]*i for i in range(1, base+1)]
        
In [52]:
triangle(6)
Out[52]:
[['*'],
 ['*', '*'],
 ['*', '*', '*'],
 ['*', '*', '*', '*'],
 ['*', '*', '*', '*', '*'],
 ['*', '*', '*', '*', '*', '*']]
In [53]:
def createrowstr(row):
    return " ".join(row)

def pretty_print(triangle):
    n = len(triangle[-1])
    width = n + (n-1) # n for items, n-1 for spaces
    for row in triangle:
        line = createrowstr(row).center(width)
        print(line)
In [56]:
def pretty_print(triangle(30))
                             *                             
                            * *                            
                           * * *                           
                          * * * *                          
                         * * * * *                         
                        * * * * * *                        
                       * * * * * * *                       
                      * * * * * * * *                      
                     * * * * * * * * *                     
                    * * * * * * * * * *                    
                   * * * * * * * * * * *                   
                  * * * * * * * * * * * *                  
                 * * * * * * * * * * * * *                 
                * * * * * * * * * * * * * *                
               * * * * * * * * * * * * * * *               
              * * * * * * * * * * * * * * * *              
             * * * * * * * * * * * * * * * * *             
            * * * * * * * * * * * * * * * * * *            
           * * * * * * * * * * * * * * * * * * *           
          * * * * * * * * * * * * * * * * * * * *          
         * * * * * * * * * * * * * * * * * * * * *         
        * * * * * * * * * * * * * * * * * * * * * *        
       * * * * * * * * * * * * * * * * * * * * * * *       
      * * * * * * * * * * * * * * * * * * * * * * * *      
     * * * * * * * * * * * * * * * * * * * * * * * * *     
    * * * * * * * * * * * * * * * * * * * * * * * * * *    
   * * * * * * * * * * * * * * * * * * * * * * * * * * *   
  * * * * * * * * * * * * * * * * * * * * * * * * * * * *  
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
In [58]:
def totext(data):
    return [[str(item) for item in row] for row in data]

pretty_print(totext(pascal(5)))
    1    
   1 1   
  1 2 1  
 1 3 3 1 
1 4 6 4 1
In [59]:
pretty_print(totext(pascal(6)))
     1     
    1 1    
   1 2 1   
  1 3 3 1  
 1 4 6 4 1 
1 5 10 10 5 1

Working with files

In [60]:
%%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 [62]:
with open("poem.txt") as f:
    print(f.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 [64]:
with open("poem.txt") as f:
    for line in f:
        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 [65]:
with open("poem.txt") as f:
    for i, line in enumerate(f):
        print(i+1, line, end="")
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 [66]:
f = open("poem.txt")
In [67]:
f.readline()
Out[67]:
'The Zen of Python, by Tim Peters\n'
In [68]:
f.readline()
Out[68]:
'\n'
In [69]:
f.readline()
Out[69]:
'Beautiful is better than ugly.\n'
In [70]:
f.readlines()
Out[70]:
['Explicit is better than implicit.\n',
 'Simple is better than complex.\n',
 'Complex is better than complicated.\n',
 'Flat is better than nested.\n',
 'Sparse is better than dense.\n',
 'Readability counts.\n',
 "Special cases aren't special enough to break the rules.\n",
 'Although practicality beats purity.\n',
 'Errors should never pass silently.\n',
 'Unless explicitly silenced.\n',
 'In the face of ambiguity, refuse the temptation to guess.\n',
 'There should be one-- and preferably only one --obvious way to do it.\n',
 "Although that way may not be obvious at first unless you're Dutch.\n",
 'Now is better than never.\n',
 'Although never is often better than *right* now.\n',
 "If the implementation is hard to explain, it's a bad idea.\n",
 'If the implementation is easy to explain, it may be a good idea.\n',
 "Namespaces are one honking great idea -- let's do more of those!\n"]
In [71]:
for line in f:
    print(line, end="")
In [72]:
r = reversed(range(5))
In [73]:
for i in r:
    print(i)
4
3
2
1
0
In [74]:
for i in r:
    print(i)

problems

  • Write a python script cat.py which prints contents of file to standard output
  • Write a python script head.py which prints first n lines of file.
python head.py 3 poem.txt
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
  • Write a python script wc.py which mimics unix command wc. it should show linecount, wordcount and charcount.
python wc.py poem.txt
21 144 857 poem.txt
  • Write a python script tail.py which shows last n lines of file.
python tail.py 3 poem.txt
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!
  • Find longest line from file.
In [75]:
!wc poem.txt
 21 144 857 poem.txt
In [76]:
!cat 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 [78]:
!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 [79]:
!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 [80]:
%%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 [83]:
%%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 [84]:
!python head.py 3 poem.txt
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
In [85]:
%%file wc.py
import sys

def linecount(file):
    with open(file) as f:
        return len(f.readlines())
    
    
def wordcount(file):
    with open(file) as f:
        return len(f.read().strip().split())
    
    
def charcount(file):
    with open(file) as f:
        return len(f.read())
    
if __name__ == "__main__":
    f = sys.argv[1]
    print(linecount(f), wordcount(f), charcount(f), f)
Writing wc.py
In [86]:
!python wc.py poem.txt
21 144 857 poem.txt
In [87]:
l = [1, 2, 3, 4, 5, 6, 7, 8]
In [88]:
l[2:]
Out[88]:
[3, 4, 5, 6, 7, 8]
In [89]:
l[:5]
Out[89]:
[1, 2, 3, 4, 5]
In [90]:
l[:-3]
Out[90]:
[1, 2, 3, 4, 5]
In [91]:
l[-3:]
Out[91]:
[6, 7, 8]
In [92]:
n = len(l)
In [93]:
l[3-n:]
Out[93]:
[4, 5, 6, 7, 8]
In [94]:
l[-3:]
Out[94]:
[6, 7, 8]
In [103]:
%%file tail.py

import sys

def tail(file, n):
    with open(file) as f:
        lines = f.readlines()
        for line in lines[-n:]:
            print(line, end="")
            
            
            
def efficient_tail(file, n):
    with open(file) as f:
        window = [""]*n
        for line in f:
            window.append(line)
            window.pop(0)
        for line in window:
            print(line, end="")
            
if __name__ == "__main__":
    file = sys.argv[2]
    n = int(sys.argv[1])
    efficient_tail(file, n)
Overwriting tail.py
In [104]:
!python tail.py 4 poem.txt
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]:
l.pop?

different modes of opening file

   "w" -> Write text->
   "a" -> append text
   "b" -> binary
   "rb" -> read binary
   "wb" -> write binary->
In [105]:
with open("numbers.txt", "w") as f:
    f.write("one\n")
    f.write("tow\n")
    f.write("three\n")
In [106]:
!python cat.py numbers.txt
one
tow
three

In [109]:
with open("numbers.txt", "w") as f: # this will over write existing contents
    f.write("one\n")
    f.write("two\n")
    f.write("three\n")
In [110]:
!python cat.py numbers.txt
one
two
three

In [111]:
with open("numbers.txt", "a") as f:
    f.write("four\n")
    f.write("five\n")
In [112]:
!python cat.py numbers.txt
one
two
three
four
five

In [113]:
b'four'
Out[113]:
b'four'

Working with dictionary

In [115]:
person = {"name":"Alice",
          "email":"alice@wonder.land",
          "language":"english"
         }
In [116]:
person['name']
Out[116]:
'Alice'
In [117]:
person['country']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-117-ecd84166211a> in <module>
----> 1 person['country']

KeyError: 'country'
In [118]:
person.get("country","UK")
Out[118]:
'UK'
In [119]:
person
Out[119]:
{'name': 'Alice', 'email': 'alice@wonder.land', 'language': 'english'}
In [120]:
del person['email']
In [121]:
person
Out[121]:
{'name': 'Alice', 'language': 'english'}
In [122]:
person['email'] = "alice@wonder.land"

Example - Word frequency

In [123]:
%%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
six seven eight nine
six seven eight
six seven
six
Writing words.txt
In [124]:
def wordfreq(words):
    freq = {}
    
    for w in words:
        if w in freq:
            freq[w] += 1
        else:
            freq[w] = 1
    return freq
In [125]:
def getwords(file):
    with open(file) as f:
        return f.read().strip().split()
In [126]:
words = getwords("words.txt")
In [127]:
wordfreq(words)
Out[127]:
{'one': 9,
 'two': 7,
 'three': 5,
 'four': 3,
 'five': 1,
 'six': 9,
 'seven': 7,
 'eight': 5,
 'nine': 3,
 'ten': 1}
In [128]:
def wordfreq1(words):
    freq = {}
    
    for w in words:
        freq[w] = freq.get(w, 0) + 1

    return freq
In [129]:
wordfreq1(words)
Out[129]:
{'one': 9,
 'two': 7,
 'three': 5,
 'four': 3,
 'five': 1,
 'six': 9,
 'seven': 7,
 'eight': 5,
 'nine': 3,
 'ten': 1}
In [130]:
def wordfreq2(words):
    unique = set(words)
    freq = {}
    for w in unique:
        freq[w] = words.count(w)
    return freq
In [131]:
wordfreq2(words)
Out[131]:
{'two': 7,
 'seven': 7,
 'nine': 3,
 'four': 3,
 'eight': 5,
 'five': 1,
 'three': 5,
 'six': 9,
 'one': 9,
 'ten': 1}
In [133]:
def wordfreq3(words):
    unique = set(words)
    return {w:words.count(w) for w in unique}
In [135]:
wordfreq3(words)
Out[135]:
{'two': 7,
 'seven': 7,
 'nine': 3,
 'four': 3,
 'eight': 5,
 'five': 1,
 'three': 5,
 'six': 9,
 'one': 9,
 'ten': 1}
In [137]:
freq = wordfreq(words)
In [138]:
for w in sorted(freq):
    print(w, freq[w])
eight 5
five 1
four 3
nine 3
one 9
seven 7
six 9
ten 1
three 5
two 7
In [140]:
for w in sorted(freq, key=lambda w: freq[w], reverse=True):
    print(w, freq[w])
one 9
six 9
two 7
seven 7
three 5
eight 5
four 3
nine 3
five 1
ten 1
In [141]:
for w in sorted(freq, key=lambda w: freq[w], reverse=True):
    print(w.rjust(5), freq[w])
  one 9
  six 9
  two 7
seven 7
three 5
eight 5
 four 3
 nine 3
 five 1
  ten 1
In [142]:
for w in sorted(freq, key=lambda w: freq[w], reverse=True):
    print(w.rjust(5), freq[w], freq[w]*"*")
  one 9 *********
  six 9 *********
  two 7 *******
seven 7 *******
three 5 *****
eight 5 *****
 four 3 ***
 nine 3 ***
 five 1 *
  ten 1 *
In [143]:
for w in freq:
    print(w)
one
two
three
four
five
six
seven
eight
nine
ten
In [144]:
for w,f in freq.items():
    print(w.rjust(5), f, f*"*")
  one 9 *********
  two 7 *******
three 5 *****
 four 3 ***
 five 1 *
  six 9 *********
seven 7 *******
eight 5 *****
 nine 3 ***
  ten 1 *
In [146]:
for f in freq.values():
    print(f, end=",")
9,7,5,3,1,9,7,5,3,1,
In [148]:
sorted([1, 2, 3, 4, 5], key=lambda x: 5)
Out[148]:
[1, 2, 3, 4, 5]
In [149]:
names = ['Elsa',"Alex","Alice","Elisa"]
surnames = ["Frozen", "Lion","Wonder","Hacker"]
dict(zip(names, surnames))
Out[149]:
{'Elsa': 'Frozen', 'Alex': 'Lion', 'Alice': 'Wonder', 'Elisa': 'Hacker'}

problem

  • Read a config file given below and load it as dictionary.
    >>> loadconfig("config.cfg")
    {"processor":"Corei5","os":"Mint","memory":"16GB"}
In [150]:
%%file config.cfg
processor=Corei5
os=mint
memory=16GB
Writing config.cfg
In [151]:
def loadconfig(file):
    with open(file) as f:
        conf = {}
        for line in f:
            k,v = line.strip().split("=")
            conf[k] = v
        return conf
In [152]:
loadconfig("config.cfg")
Out[152]:
{'processor': 'Corei5', 'os': 'mint', 'memory': '16GB'}
In [153]:
def loadconfig(file):
    with open(file) as f:
         return dict([line.strip().split("=") for line in f])
In [154]:
loadconfig("config.cfg")
Out[154]:
{'processor': 'Corei5', 'os': 'mint', 'memory': '16GB'}
In [155]:
def loadconfig(file):
    with open(file) as f:
         return {k:v for k,v in [line.strip().split("=") for line in f]}
In [156]:
loadconfig("config.cfg")
Out[156]:
{'processor': 'Corei5', 'os': 'mint', 'memory': '16GB'}
In [157]:
tables = [[i*j for i in range(1,6)] for j in range(1,11)]
In [158]:
tables
Out[158]:
[[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]]

problems

  • Write a function writecsv to write csv file for tabular data.
    %%file data.csv
    1,2,3,4,5
    2,4,6,8,10
    .
    .
    .
  • Write a function parsecsv to read csv file and load data as 2D list of integers
In [163]:
def writecsv(data, file):
    with open(file, "w") as f:
        for row in data:
            line = ",".join([str(item) for item in row])
            f.write(line)
            f.write("\n")
            
In [164]:
writecsv(tables, "tables.csv")
In [165]:
!python cat.py tables.csv
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 [166]:
def parsecsv(file):
    with open(file) as f:
        data = []
        for line in f:
            items = line.strip().split(",")
            data.append([int(i) for i in items])
        return data
In [167]:
parsecsv("tables.csv")
Out[167]:
[[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]]

environment

In [168]:
a = 10
def foo():
    a = 20
    
print(a)
10
In [170]:
x = [1, 1, 1, 0]
def foo():
    x = [0,0,0]
    
foo()
print(x)
[1, 1, 1, 0]
In [171]:
x = [1, 1, 1]

def foo():
    x.append(0)
    
foo()

print(x)
[1, 1, 1, 0]
In [172]:
x = [1, 1, 1]

def foo():
    x = x + [1]
    
foo()
print(x)
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-172-3bab97f55b1d> in <module>
      4     x = x + [1]
      5 
----> 6 foo()
      7 print(x)

<ipython-input-172-3bab97f55b1d> in foo()
      2 
      3 def foo():
----> 4     x = x + [1]
      5 
      6 foo()

UnboundLocalError: local variable 'x' referenced before assignment
In [173]:
x = [1, 1, 1]

def foo():
    x =  [1]
    
foo()
print(x)
[1, 1, 1]
In [ ]:
x = [1, 1, 1]

def foo(y):
    y.append(0)
    
foo(x)
print(x)

classes

In [174]:
%%file bank.py

balance = 0

def withdraw(amount):
    global balance
    balance -= amount
    
def deposit(amount):
    global balance
    balance += amount
    
    
def get_balance():
    return balance

if __name__ == "__main__":
    pass
Writing bank.py
In [175]:
import bank
In [176]:
bank.get_balance()
Out[176]:
0
In [177]:
bank.deposit(10000)
In [178]:
bank.withdraw(2323)
In [179]:
bank.get_balance()
Out[179]:
7677
In [180]:
%%file bank1.py


def make_account():
    return {"balance":0}

def get_balance(account):
    return account['balance']

def withdraw(account, amount):
    account['balance'] -= amount
    
def deposit(account, amount):
    account['balance'] += amount
Writing bank1.py
In [181]:
import bank1
In [182]:
a1 = bank1.make_account()
In [183]:
a2 = bank1.make_account()
In [184]:
bank1.deposit(a1, 10000)
bank1.deposit(a2, 2000)
In [185]:
bank1.withdraw(a1, 2323)
In [186]:
print(bank1.get_balance(a1))
print(bank1.get_balance(a2))
7677
2000
In [187]:
class BankAccount:
    
    def __init__(self):
        self.balance = 0
        
    def get_balance(self):
        return self.balance
    
    def deposit(self, amount):
        self.balance += amount
        
    def withdraw(self, amount):
        self.balance -= amount
In [188]:
a1 = BankAccount()
In [189]:
a1.get_balance()
Out[189]:
0
In [190]:
a1.deposit(10000)
In [191]:
a1.withdraw(3243)
In [192]:
a1.get_balance()
Out[192]:
6757
In [193]:
a2 = BankAccount()
In [194]:
a2.deposit(23323)
In [195]:
a1.balance
Out[195]:
6757
In [196]:
a2.balance
Out[196]:
23323
In [197]:
class BankAccount:
    
    def __init__(self):
        self._balance = 0 # a convention for private attribute
        
    def get_balance(self):
        return self.balance
    
    def deposit(self, amount):
        self.balance += amount
        
    def withdraw(self, amount):
        self.balance -= amount
In [198]:
a1 = BankAccount()
In [199]:
a1._balance
Out[199]:
0
In [200]:
a1.__dict__
Out[200]:
{'_balance': 0}
In [201]:
class Foo:
    pass
In [202]:
f = Foo()
In [203]:
f.x = 10
In [204]:
f.x
Out[204]:
10

inheritance

In [205]:
class Point:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
class RedPoint(Point):
    color = "red"
In [206]:
p = Point(3, 4)
In [207]:
r1 = RedPoint(0, 0)
In [208]:
p.x,p.y
Out[208]:
(3, 4)
In [209]:
r1.x, r1.y
Out[209]:
(0, 0)
In [210]:
r1.color
Out[210]:
'red'
In [211]:
r2 = RedPoint(5,6)
In [212]:
r2.color
Out[212]:
'red'
In [213]:
RedPoint.color
Out[213]:
'red'
In [214]:
RedPoint.color = "RED"
In [215]:
r1.color
Out[215]:
'RED'
In [216]:
r2.color
Out[216]:
'RED'
In [217]:
r2.color = "red"
In [218]:
RedPoint
Out[218]:
__main__.RedPoint
In [219]:
r1.color
Out[219]:
'RED'
In [220]:
RedPoint.color
Out[220]:
'RED'
In [221]:
r1.__dict__
Out[221]:
{'x': 0, 'y': 0}
In [222]:
r2.__dict__
Out[222]:
{'x': 5, 'y': 6, 'color': 'red'}

problem

  • Write a class Timer which will have following methods, start, stop, elapsed_time
    t = Timer()
    t.start()
    task()
    t.stop()
    print("Time taken by taks:", t.elapsed_time())
    `
In [223]:
import time
In [224]:
time.time()
Out[224]:
1569326172.0296404
In [228]:
class Timer:
    
    
    def start(self):
        self._start = time.time()
    
    def stop(self):
        self._end = time.time()
    
    def reset(self):
        self._start = 0
        self._end = 0
    
    def elapsed_time(self):
        return self._end - self._start
In [229]:
t = Timer()
t.start()
time.sleep(2)
t.stop()
print("Time taken:",t.elapsed_time())
Time taken: 2.002462148666382
In [230]:
l
Out[230]:
[1, 2, 3, 4, 5, 6, 7, 8]
In [231]:
str(l)
Out[231]:
'[1, 2, 3, 4, 5, 6, 7, 8]'
In [232]:
class Pair:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return "Pair({},{})".format(self.x, self.y)
    
    
    def __str__(self):
        return "<{},{}>".format(self.x, self.y)
In [233]:
p = Pair(2,3)
In [234]:
p
Out[234]:
Pair(2,3)
In [235]:
r1
Out[235]:
<__main__.RedPoint at 0x7fd7b54d21d0>
In [237]:
Point(0,0)
Out[237]:
<__main__.Point at 0x7fd7b4542400>
In [238]:
print(p)
<2,3>
In [239]:
class Pair:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return "Pair({},{})".format(self.x, self.y)
    
    
    def __str__(self):
        return "<{},{}>".format(self.x, self.y)
    
    
    def __add__(self, p):
        return Pair(self.x + p.x , self.y + p.y)
    
    def __eq__(self, p):
        return self.x==p.x and self.y==p.y
In [240]:
p1 = Pair(3,4)
In [241]:
p2 = Pair(5,6)
In [242]:
p1 + p2
Out[242]:
Pair(8,10)
In [243]:
p1 == p2
Out[243]:
False
In [244]:
p3 = Pair(3, 4)
In [245]:
p1 == p3
Out[245]:
True
In [246]:
p = Point(3, 4)
In [247]:
p
Out[247]:
<__main__.Point at 0x7fd7b44bda58>
In [248]:
type(p)
Out[248]:
__main__.Point
In [249]:
type(p1)
Out[249]:
__main__.Pair
In [250]:
isinstance(p1, Pair)
Out[250]:
True
In [251]:
isinstance(p, Point)
Out[251]:
True
In [252]:
isinstance(r1, Point)
Out[252]:
True
In [253]:
class Pair:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return "Pair({},{})".format(self.x, self.y)
    
    
    def __str__(self):
        return "<{},{}>".format(self.x, self.y)
    
    
    def __add__(self, p):
        return Pair(self.x + p.x , self.y + p.y)
    
    def __eq__(self, p):
        return self.x==p.x and self.y==p.y
    
    def __getitem__(self, name):
        if name == "x":
            return self.x
        elif name == "y":
            return self.y
        else:
            raise KeyError("No such item", name)
In [254]:
p = Pair(4,5)
In [256]:
p['x']
Out[256]:
4
In [257]:
p['y']
Out[257]:
5
In [258]:
p['z']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-258-de2b26327b77> in <module>
----> 1 p['z']

<ipython-input-253-70de590ec1d3> in __getitem__(self, name)
     25             return self.y
     26         else:
---> 27             raise KeyError("No such item", name)

KeyError: ('No such item', 'z')
In [260]:
type(1)
Out[260]:
int

Example : shape modeling

In [264]:
%matplotlib inline
In [278]:
from functools import reduce
from matplotlib.pyplot import imshow



class Shape:
    
    def contains(self, p):
        pass
    
class Point:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        

class Rectangle(Shape):
    
    def __init__(self, width, length):
        self.w = width
        self.l = length
        
    def contains(self, p):
        return p.x <= self.w and p.y <= self.l
    
class Circle(Shape):
    
    def __init__(self, radius):
        self.r = radius
        
    def contains(self, p):
        return (p.x**2 + p.y**2)**0.5 <= self.r
    
class Union(Shape):
    
    def __init__(self, shapes):
        self.shapes = shapes
        
    def contains(self, p):
        conds = [s.contains(p) for s in self.shapes]
        return reduce(lambda x,y: x or y, conds, False)
    
class Intersection(Shape):
    
    def __init__(self, shapes):
        self.shapes = shapes
        
    def contains(self, p):
        conds = [s.contains(p) for s in self.shapes]
        return reduce(lambda x,y: x and y, conds, True)
    
class Canvas:
    
    def __init__(self, w=1000, l=1000):
        self.w = w
        self.l = l
        
        self.display = [[False for i in range(w)] for j in range(l)]
        
    def draw(self, shape):
        def translate(p):
            return Point(self.w//2 - p.x, self.l//2 -p.y)
    
        self.display = [[shape.contains(translate(Point(i,j))) for i in range(self.w)] for j in range(self.l)]
    
    def plot(self):
        imshow(self.display)
In [279]:
c = Circle(50)
canvas = Canvas(100,100)
canvas.draw(c)
canvas.plot()
In [280]:
c1 = Circle(50)
r1 = Rectangle(10, 120)
u = Union([c1, r1])
inter = Intersection([c1, r1])
In [281]:
canvas = Canvas(200, 200)
canvas.draw(u)
canvas.plot()
In [282]:
canvas = Canvas(200, 200)
canvas.draw(inter)
canvas.plot()

Further references

In [283]:
import openpyxl
/home/vikrant/anaconda3/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject
  return f(*args, **kwds)
In [ ]: