Module II - Day 1

Python Made Easy: Science and Math Edition

Sep-Dec 2025 batch, Vikrant Patil

Date: 01 Nov 2025

Click here for All Notes

© Vikrant Patil

modules

in order to execute functionality from a module we have to import it first

import random
random
<module 'random' from '/usr/lib/python3.11/random.py'>
random.random() # random.random is a function that generates a random number between 0 to 1
0.8821510380165588
random.choice([2, 3, 1, 4, 5, 7, 5])
1
random.choice(range(1, 101)) # choose a random number from 1 to 100
75
range(10) # 0 -9
range(0, 10)
range(5, 15) # 5 to 14
range(5, 15)
import datetime
datetime.datetime.now() # date, time for now!
datetime.datetime(2025, 11, 1, 20, 15, 32, 273715)
datetime.datetime.now()
datetime.datetime(2025, 11, 1, 20, 15, 51, 450931)
d1 = datetime.datetime.now()
import time
time.sleep(2) # just wait for 2 seconds
d2 = datetime.datetime.now()
d1
datetime.datetime(2025, 11, 1, 20, 16, 13, 692981)
d2
datetime.datetime(2025, 11, 1, 20, 17, 2, 666447)
d2 > d1
True
type(datetime.datetime)
type
type(datetime)
module
"hello".endswith("o")
True
date = datetime.datetime(year=2024, month=11, day=10)
# jupyter functionality
datetime.datetime.strptime?
Docstring: string, format -> new datetime parsed from a string (like time.strptime()).
Type:      builtin_function_or_method
help(datetime.datetime.strptime)
Help on built-in function strptime:

strptime(...) method of builtins.type instance
    string, format -> new datetime parsed from a string (like time.strptime()).
desired_date = datetime.datetime.strptime("2025-11-01", "%Y-%m-%d")
desired_date + datetime.timedelta(days=1)
datetime.datetime(2025, 11, 2, 0, 0)
desired_date
datetime.datetime(2025, 11, 1, 0, 0)
desired_date  + datetime.timedelta(days=1)
datetime.datetime(2025, 11, 2, 0, 0)

problems

  • write a function drange which geneartes dates from start date to whatever n days you specify as paramter.
>>> drange(datetime.datetime(2025, 11, 2, 0, 0), 5)
[datetime.datetime(2025, 11, 2, 0, 0),
 datetime.datetime(2025, 11, 3, 0, 0),
 datetime.datetime(2025, 11, 4, 0, 0),
 datetime.datetime(2025, 11, 5, 0, 0),
 datetime.datetime(2025, 11, 6, 0, 0)]
def square(x):
    return x ** 2
    
square("ere")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[45], line 1
----> 1 square("ere")

Cell In[44], line 2, in square(x)
      1 def square(x):
----> 2     return x ** 2

TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
"dasd" ** 2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[46], line 1
----> 1 "dasd" ** 2

TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
def power(x, y):
    return x  ** y
power(2, "fsdf")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[48], line 1
----> 1 power(2, "fsdf")

Cell In[47], line 2, in power(x, y)
      1 def power(x, y):
----> 2     return x  ** y

TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'str'
def add(x, y):
    return x + y
add("sdfsdf", "asdasd")
'sdfsdfasdasd'
add([1, 2, 3, 4], [1,1,1])
[1, 2, 3, 4, 1, 1, 1]
add("sadasd", 5)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[52], line 1
----> 1 add("sadasd", 5)

Cell In[49], line 2, in add(x, y)
      1 def add(x, y):
----> 2     return x + y

TypeError: can only concatenate str (not "int") to str
add(5, "dfd")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[53], line 1
----> 1 add(5, "dfd")

Cell In[49], line 2, in add(x, y)
      1 def add(x, y):
----> 2     return x + y

TypeError: unsupported operand type(s) for +: 'int' and 'str'
range(5)
range(0, 5)
range("dfgd")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[55], line 1
----> 1 range("dfgd")

TypeError: 'str' object cannot be interpreted as an integer
import math as m # give alias to imported module
m.sqrt(4)
2.0
import math
math.sqrt(4)
2.0
from random import choice
choice([12, 34, 5, 2, 3, 5])
2

os module

import os
os.listdir()
['students-module1-day4.ipynb',
 'about.qmd~',
 'index.qmd',
 'students-batch',
 'topics.qmd~',
 'notes.qmd',
 '_quarto.yml',
 'notes.qmd~',
 'push',
 'styles.css',
 'module1-day5.ipynb',
 'trainer.qmd',
 'promotions',
 '.quarto',
 'index.qmd~',
 '_quarto.yml~',
 '_site',
 '.gitignore',
 'students-module1-day2.ipynb',
 'module1-day1.ipynb',
 'module1-day2.ipynb',
 'topics.qmd',
 'module2-day1.ipynb',
 'trainer.qmd~',
 'module1-day3.ipynb',
 'Makefile~',
 'students-module1-day3.ipynb',
 'Makefile',
 '.ipynb_checkpoints',
 'module1-day4.ipynb',
 'today.org']
os.listdir()  # this function returns a list of all the files in current working directory /folder
['students-module1-day4.ipynb',
 'about.qmd~',
 'index.qmd',
 'students-batch',
 'topics.qmd~',
 'notes.qmd',
 '_quarto.yml',
 'notes.qmd~',
 'push',
 'styles.css',
 'module1-day5.ipynb',
 'trainer.qmd',
 'promotions',
 '.quarto',
 'index.qmd~',
 '_quarto.yml~',
 '_site',
 '.gitignore',
 'students-module1-day2.ipynb',
 'module1-day1.ipynb',
 'module1-day2.ipynb',
 'topics.qmd',
 'module2-day1.ipynb',
 'trainer.qmd~',
 'module1-day3.ipynb',
 'Makefile~',
 'students-module1-day3.ipynb',
 'Makefile',
 '.ipynb_checkpoints',
 'module1-day4.ipynb',
 'today.org']
os.listdir("/home/vikrant/programming/explorations/scheme/")
['bezier.lsp',
 'p1.scm',
 'sicp',
 'treesum.scm~',
 'Untitled.ipynb',
 'problem-set4.scm',
 'treesum.scm',
 '.ipynb_checkpoints',
 '.svn']
os.listdir()
['index.html',
 'students-module1-day4.ipynb',
 'notes.html',
 'about.qmd~',
 'index.qmd',
 'students-batch',
 'topics.qmd~',
 'module1-day5.html',
 'notes.qmd',
 '_quarto.yml',
 'notes.qmd~',
 'push',
 'styles.css',
 'module1-day5.ipynb',
 'trainer.qmd',
 'promotions',
 '.quarto',
 'students-module1-day2.html',
 'index.qmd~',
 'topics.html',
 'trainer.html',
 '_quarto.yml~',
 '_site',
 'module1-day4_files',
 'module1-day1.html',
 '.gitignore',
 'students-module1-day2.ipynb',
 'module1-day1.ipynb',
 'module1-day2.ipynb',
 'topics.qmd',
 'module2-day1.ipynb',
 'module1-day3.html',
 'trainer.qmd~',
 'site_libs',
 'module1-day2.html',
 'module1-day3.ipynb',
 'Makefile~',
 'students-module1-day3.html',
 'module1-day4.html',
 'students-module1-day3.ipynb',
 'Makefile',
 'module2-day1.html',
 '.ipynb_checkpoints',
 'module1-day4.ipynb',
 'today.org',
 'students-module1-day4.html']
os.getcwd()
'/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math'
for file in os.listdir():
    completepath = os.path.join(os.getcwd(), file)
    print(completepath)
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/students-module1-day4.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/about.qmd~
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/index.qmd
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/students-batch
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/topics.qmd~
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/notes.qmd
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/_quarto.yml
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/notes.qmd~
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/push
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/styles.css
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/module1-day5.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/trainer.qmd
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/promotions
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/.quarto
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/index.qmd~
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/_quarto.yml~
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/_site
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/.gitignore
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/students-module1-day2.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/module1-day1.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/module1-day2.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/topics.qmd
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/module2-day1.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/trainer.qmd~
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/module1-day3.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/Makefile~
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/students-module1-day3.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/Makefile
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/.ipynb_checkpoints
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/module1-day4.ipynb
/home/vikrant/programming/work/github/vikrant.dev/python-made-easy-science-math/today.org

more about functions

def drage(startdate, n):
    dates = []
    for i in range(n):
        dates.append(startdate + datetime.timedelta(days=i))
    return dates
drage(d1, 5)
[datetime.datetime(2025, 11, 1, 20, 16, 13, 692981),
 datetime.datetime(2025, 11, 2, 20, 16, 13, 692981),
 datetime.datetime(2025, 11, 3, 20, 16, 13, 692981),
 datetime.datetime(2025, 11, 4, 20, 16, 13, 692981),
 datetime.datetime(2025, 11, 5, 20, 16, 13, 692981)]
drage(startdate=d1, n=5)
[datetime.datetime(2025, 11, 1, 20, 16, 13, 692981),
 datetime.datetime(2025, 11, 2, 20, 16, 13, 692981),
 datetime.datetime(2025, 11, 3, 20, 16, 13, 692981),
 datetime.datetime(2025, 11, 4, 20, 16, 13, 692981),
 datetime.datetime(2025, 11, 5, 20, 16, 13, 692981)]
def add_(a, b):
    return a + b
def add(a, b=5): # default argument
    return a + b
add(5, 6)
11
add(5) # here a = 5 and b = 5
10
add(0)
5
add(9)
14
add(9, 9)
18
add(a=9, b=7)
16
add(b=7, a=8)
15
def func(x, y):
    return x**2 + y
func(4, 5)
21
func(5, 4)
29
import math

def cylinder_volume(radius, height):
    return math.pi*radius**2 * height
cylinder_volume(2, 1)
12.566370614359172
cylinder_volume(1, 2)
6.283185307179586
cylinder_volume(radius=2, height=1)
12.566370614359172
cylinder_volume(height=1, radius=2)
12.566370614359172
def cylinder_volume(radius, height=1): # default argument
    return math.pi*radius**2 * height
def cylinder_volume( height=1, radius): # default argument
    return math.pi*radius**2 * height
  Cell In[99], line 1
    def cylinder_volume( height=1, radius): # default argument
                                   ^
SyntaxError: non-default argument follows default argument
def cylinder_volume(radius=3, height=1): # default argument
    return math.pi*radius**2 * height
cylinder_volume()
28.274333882308138
def sumofsquares(x, y):
    return square(x) + square(y)
def cube(x):
    return x**3
    
def sumofcubes(x, y):
    return cube(x) + cube(y)
def sumof(x, y, func):
    return func(x) + func(y)
sumofsquares(45, 67)
6514
sumof(45, 67, square)
6514
sumof(45, 67, cube)
391888
sumofcubes(45, 67)
391888

Reading Files

%%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
os.listdir()
['students-module1-day4.ipynb',
 'about.qmd~',
 'index.qmd',
 'students-batch',
 'topics.qmd~',
 'notes.qmd',
 '_quarto.yml',
 'notes.qmd~',
 'push',
 'styles.css',
 'module1-day5.ipynb',
 'trainer.qmd',
 'promotions',
 '.quarto',
 'index.qmd~',
 '_quarto.yml~',
 '_site',
 '.gitignore',
 'students-module1-day2.ipynb',
 'module1-day1.ipynb',
 'module1-day2.ipynb',
 'topics.qmd',
 'module2-day1.ipynb',
 'trainer.qmd~',
 'module1-day3.ipynb',
 'Makefile~',
 'poem.txt',
 'students-module1-day3.ipynb',
 'Makefile',
 '.ipynb_checkpoints',
 'module1-day4.ipynb',
 'today.org']
with open("poem.txt") as f:
    filetext = f.read()
print(filetext)
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!
with open("poem.txt") as f:
    print(f.readline())
The Zen of Python, by Tim Peters
with open("poem.txt") as f:
    print(f.readline())
    print(f.readline())
The Zen of Python, by Tim Peters


with open("poem.txt") as f:
    print(f.readline())
    print(f.readline())
    print(f.readline())
The Zen of Python, by Tim Peters



Beautiful is better than ugly.
with open("poem.txt") as f:
    for line in f:
        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!
print("x")
print("y")
x
y
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!
with open("poem.txt") as f:
    linenum = 1
    for line in f:
        print(linenum, line, end="")
        linenum = linenum + 1
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!

scripts

%%file cat.py
import sys

print(sys.argv)

filename = sys.argv[1]

with open(filename) as f:
    print(f.read())
Overwriting cat.py
%%file testargs.py

import sys

print(sys.argv)
Writing testargs.py
%%file cat.py
import sys

filename = sys.argv[1]

with open(filename) as f:
    print(f.read())
Overwriting cat.py
!ls
about.qmd~      module2-day1.ipynb       students-module1-day3.ipynb
cat.py          notes.qmd            students-module1-day4.ipynb
index.qmd       notes.qmd~           styles.css
index.qmd~      poem.txt             testargs.py
Makefile        promotions           today.org
Makefile~       push             topics.qmd
module1-day1.ipynb  _quarto.yml          topics.qmd~
module1-day2.ipynb  _quarto.yml~         trainer.qmd
module1-day3.ipynb  _site            trainer.qmd~
module1-day4.ipynb  students-batch
module1-day5.ipynb  students-module1-day2.ipynb
!dir
about.qmd~      module2-day1.ipynb       students-module1-day3.ipynb
cat.py          notes.qmd            students-module1-day4.ipynb
index.qmd       notes.qmd~           styles.css
index.qmd~      poem.txt             testargs.py
Makefile        promotions           today.org
Makefile~       push             topics.qmd
module1-day1.ipynb  _quarto.yml          topics.qmd~
module1-day2.ipynb  _quarto.yml~         trainer.qmd
module1-day3.ipynb  _site            trainer.qmd~
module1-day4.ipynb  students-batch
module1-day5.ipynb  students-module1-day2.ipynb
!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!