Module I - Day 3

Python Foundation

Nov-Jan 2025 batch, Vikrant Patil

Date: 26 Nov 2025

Click here for All Notes

login to https://traininghub.vikrant.dev/ with your username and create a notebook with name module1-day3.ipynb

© Vikrant Patil

def count_digits(n):
    return len(str(n))
count_digits(2**100)
31
def sum_naturals(n):
    """this function sums first n natural numbers
    """
    return sum(range(1, n+1))
help(sum_naturals)
Help on function sum_naturals in module __main__:

sum_naturals(n)
    this function sums first n natural numbers
sum_naturals(10)
55
nums = [1, 2, 3]
[1, 2, 3, 3, 2, 1]
nums[::-1] # this will reverse the list
nums + nums[::-1]
def symmetric_join(items):
    return items + items[::-1]
symmetric_join([1, 2, 3])
[1, 2, 3, 3, 2, 1]

palindrom is some text/list that reads same from both sides

def is_palindrom(text):
    return text == text[::-1] # == is for comparing if they are equal
is_palindrom("madam")
True
is_palindrom("sir")
False

conditions

if condition:
    do something
else:
    alternative path

onle one of the blocks will be executed even if multiple are true. If multiple conditions are true in if/elif statements then first true statement will exucute its code block

if codition1:
    procedure1
elif condition2:
    procedure2
elif condition3:
    procedure3
else:
    alternative
x, y = 42, 45
x == y # check if x is equal to y
False
x != y # check if x is not equal to y
True
x > y # check if x > y
False
x < y
True
x >= y
False
x <= y
True
text = "Python programming class"
"Python" in text
True
"java" not in text
True
x == y and "Python" in text 
False
(x == y) and ("Python" in text) 
False
x == y or "Python" in text 
True
def mymax(a, b):
    if a > b:
        return a
    else:
        return b
mymax(5, 6)
6

problem - Write a function max3 which will find maximum number from given three numbers.

>>> max3(3, 5, 8)
8
max2 = mymax # alias created for a function

def max3(x, y, z):
    m = max2(x, y)
    return max2(m, z)
    
def max3(x, y, z):
    return max2(max2(x, y), z)

def max3_(x, y, z):
    if x > y and x > z:
        return x
    elif y > z and y > x:
        return y
    else:
        return z
max3(5, 45, 3)
45
def max5(a, b, c, d, e):
    return max3(max3(a, b, c), d, e)
min([1, 2, 3, 4])
1
min(1, 2, 3)
1
max(1, 3, 5)
5

global vs local

Namespace and Functions

Everytime we call a function. With entry to function, it creates it’s own name space. And in that name space it creates names for function parameters. These names point to same location from where the pararameters are passed.

Scope of Variables

Variables defined at top level of program where main script starts are global variables. At this level globals and locals are same. Once we call a function, as soon as function execution starts, all variables created there are local to that function. Variables passed as argument to function are passed by reference. it means they refer to same object, which is passed to function. Only difference is that it is called by a different name inside the function. This is because with every function call a new namespace is created. And variables in function reside in this newly created namespace. As soon as function call is over, namespace created with function call is also deleted, so all variables in it.

Scope rules - Any name the statement refers, is looked in local scope first. - if name is not there is local scope, global scope is chacked for reading - if local name exists, then there is no way we can get global with same name

z = 10

def func(x, y):
    return x + y + z # 

Whenever you come across a variable - first it will look for local namaspace - if it is in local name space use it - if it is not there local namespace look into global namespace

Problem

What will this print?::

  x = 10
  def foo():
      x = 20 # assignemnt operator will create a local variable

  foo()
  print(x)

Problem

What will this print?

  x = 10

  def foo():
      print(x)

  foo()

Problem

What will this print?::

  x = 10

  def foo():
      x = x + 1

  foo()
  print(x)

Problem

What will this print?::

x = [1, 1, 1]

def appendzero(y): y = y + [1]

appendzero(x) print(x)

Problem

What will this print?::

x = [1, 1, 1]

def appendzero(y): y.append(0)

appendzero(x) print(x)

x = 10
def foo():
    x = 20 # assignemnt operator will create a local variable

foo()
print(x) # this statement is outside the function... will be executed in global namaspace
10
x = 10

def foo():
    print(x) # there is no local variable with name x in foo! so it will take x from global

foo()
10
x = 10

def foo():
    x = x + 1  # x is also local and global

foo()
print(x)
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
Cell In[37], line 6
      3 def foo():
      4     x = x + 1  # x is also local and global
----> 6 foo()
      7 print(x)

Cell In[37], line 4, in foo()
      3 def foo():
----> 4     x = x + 1

UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
x = 10

def foo():
    print(x + 1)  # x is global

foo()
print(x)
11
10
x = 10
def foo():
    global x # because if this statement x is modified in global context
    x = x + 1 

foo()
print(x)
11
x = [1, 1, 1]

def appendzero(a):
    a.append(0)

appendzero(x)
print(x)
[1, 1, 1, 0]
x = [1, 1, 1]

def appendone():
    x = x + [1]

appendone()
print(x)
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
Cell In[43], line 6
      3 def appendone():
      4     x = x + [1]
----> 6 appendone()
      7 print(x)

Cell In[43], line 4, in appendone()
      3 def appendone():
----> 4     x = x + [1]

UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
x = [1, 1, 1]

def appendone(a):
    a.append(1)

appendone(x)
print(x)
[1, 1, 1, 1]

Style guide for functions

def twice(x):
    print(2*x)
twice(5)
10
def double(y):
    return 2*y
twice(5) # this is a print
10
double(5) # this is a return
10
x = double(5)
x
10
y = twice(5)
10
print(y)
None
def fourtimes(x):
    return double(double(x))
fourtimes(5)
20
def fourtimes_(x):
    twice(twice(x))
twice(None)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[60], line 1
----> 1 twice(None)

Cell In[46], line 2, in twice(x)
      1 def twice(x):
----> 2     print(2*x)

TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
fourtimes_(5)
10
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[61], line 1
----> 1 fourtimes_(5)

Cell In[59], line 2, in fourtimes_(x)
      1 def fourtimes_(x):
----> 2     twice(twice(x))

Cell In[46], line 2, in twice(x)
      1 def twice(x):
----> 2     print(2*x)

TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
twice(twice(5))
10
twice(None)
10
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[63], line 1
----> 1 twice(twice(5))
      2 10
      3 twice(None)

Cell In[46], line 2, in twice(x)
      1 def twice(x):
----> 2     print(2*x)

TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
double(double(5))
20

Guidelines for writing functions

  • A function should behave as a perfect black box. it has definite inputs and definte outputs
  • it works only on given inputs.
  • A reusable function returns the computed value
  • A reusable function does not make use of gloabl variables.
  • A reusable function takes all the required inputs as arguments.

About naming - give meaningful names to variables and function, you can combine multiple words together with _ to make meaningful name - Write code to read first and then execute

more about functions

  • functions are first class objects in python
  • it means functions are treated same as variables
def sumof(func, x, y):
    return func(x) + func(y)
def square(x):
    return x*x
sumof(square, 3, 4)
25
def poly(x):
    return x**2 + 2*x + 1
sumof(poly, 3, 4)
41
def sumofsquares(x, y):
    return x**x + y**y

def sumofpoly(x, y):
    return x**2 + 2*x + 1 + y**2 + 2*y + 1
max([1, 2, 3, 4, 5, 6])
6
words = ["one", "two", "three", "four", "five", "six"]
max(words) # dictionary order
'two'
sorted(words) # sorted is built in function which will do comparison of text by dictionary order
['five', 'four', 'one', 'six', 'three', 'two']
min(words)
'five'
max(words, key=len)
'three'
sorted(words, key=len) # sort by length
['one', 'two', 'six', 'four', 'five', 'three']
records = [
    ("TATA", 200.0, 5.5),
    ("INFY", 2000.0, -5),
    ("RELIANCE", 1505.5, 50.0),
    ("HCL", 1200, 70.5)
  ]
records
[('TATA', 200.0, 5.5),
 ('INFY', 2000.0, -5),
 ('RELIANCE', 1505.5, 50.0),
 ('HCL', 1200, 70.5)]
pairs = [(1,2), (34,5), (65, 20), (23,87), (2, 45), (1, 5), (65,12)]
pairs
[(1, 2), (34, 5), (65, 20), (23, 87), (2, 45), (1, 5), (65, 12)]
sorted(pairs)
[(1, 2), (1, 5), (2, 45), (23, 87), (34, 5), (65, 12), (65, 20)]
sorted(records) # sorted dictionary order
[('HCL', 1200, 70.5),
 ('INFY', 2000.0, -5),
 ('RELIANCE', 1505.5, 50.0),
 ('TATA', 200.0, 5.5)]
def get_value(r):
    return r[1]
records[0]
('TATA', 200.0, 5.5)
get_value(records[0])
200.0
sorted(records, key=get_value)
[('TATA', 200.0, 5.5),
 ('HCL', 1200, 70.5),
 ('RELIANCE', 1505.5, 50.0),
 ('INFY', 2000.0, -5)]
def get_gain(r):
    return r[2]
sorted(records, key=get_gain)
[('INFY', 2000.0, -5),
 ('TATA', 200.0, 5.5),
 ('RELIANCE', 1505.5, 50.0),
 ('HCL', 1200, 70.5)]
sorted(records, key=get_value, reverse=True)
[('INFY', 2000.0, -5),
 ('RELIANCE', 1505.5, 50.0),
 ('HCL', 1200, 70.5),
 ('TATA', 200.0, 5.5)]
sorted(records, key=get_value)
[('TATA', 200.0, 5.5),
 ('HCL', 1200, 70.5),
 ('RELIANCE', 1505.5, 50.0),
 ('INFY', 2000.0, -5)]
help(sorted)
Help on built-in function sorted in module builtins:

sorted(iterable, /, *, key=None, reverse=False)
    Return a new list containing all items from the iterable in ascending order.

    A custom key function can be supplied to customize the sort order, and the
    reverse flag can be set to request the result in descending order.
sorted(records, get_gain, True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[99], line 1
----> 1 sorted(records, get_gain, True)

TypeError: sorted expected 1 argument, got 3
sorted(records, key=get_gain, reverse=True)
[('HCL', 1200, 70.5),
 ('RELIANCE', 1505.5, 50.0),
 ('TATA', 200.0, 5.5),
 ('INFY', 2000.0, -5)]

function arguments


def cylinder_volume(radius, height):
    return 3.14 * radius**2 * height   
cylinder_volume(2, 1) # call function with positional argument
12.56
cylinder_volume(1, 2) # the order is important!
6.28
cylinder_volume(height=1, radius=2) # named arguments
12.56

def cylinder_volume(radius, height=1): # default argument
    return 3.14 * radius**2 * height   
cylinder_volume(3) # height by default taken as 1
28.26
cylinder_volume(3, height=2)
56.52
def cylinder_volume(height=1, radius): # default argument must be given after non-default argument
    return 3.14 * radius**2 * height   
  Cell In[109], line 1
    def cylinder_volume(height=1, radius): # default argument must be given after non-default argument
                                  ^
SyntaxError: parameter without a default follows parameter with a default
def func(nondefault1, nondefault2, default1=1, default=2):
    pass

# nondefault1, nondefault2 these are positinal arguments if we pass only values while calling
# if you pass function parameters with name while calling it is called named argument

Homework

  • Write a function voice_of_wild which takes an argument of species name and prints the word associated with that species’s voice. Make use use of conditions to do this. Your function should support following species and their voice as given below
  ===========   ====================================
  species          voice                              
  ===========   ====================================
  bird            chirp      
  bat             echolocation
  cat             meow
  dog             bark
  duck            quack
  any other       Not supported
  ===========   ==================================== 
  • \(n^{th}\) Fibonacci number is a number which can be defined as given here. \(F_{n} = F_{n-1} + F_{n-2}\) Write a function fibonacci which computes \(n^{th}\) fibonacci number. if n is 0 or 1 it returns 1 else it calls back same function with arguments n-1 and n-2 (When a function calls itself it is called as recursion). Do not forget to put condition for n == 0 or n == 1 , otherwise you might end up with infinite recursion.