Python notes
Module 4
A module is a file containing Python definitions and statements that can be reused in other programs.
Types of Modules
Type Example Purpose
Standard Library Modules math, random, string, turtle Built-in functionality
User-defined Modules .py files created by users Code reuse
Using Modules
import module_name
Example:
import random
Help System
• Python provides a built-in help system
• Lists all available standard modules
help()
help(random)
Useful for exploring module functions and documentation.
8.1 Random Numbers
Why Random Numbers Are Used
Application Purpose
Games Dice, cards, coin toss
Simulations Rainfall, population models
Security Encryption
Graphics Random positions
AI/Games Enemy movement
random Module
Python provides the random module to generate random values.
Creating a Random Generator Object
import random
rng = [Link]()
rng acts as a random number generator (black box)
1 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
randrange() Method
dice_throw = [Link](1, 7)
Feature Description
Range 1 to 6
Lower bound Included
Upper bound Excluded
Distribution Uniform
Random Odd Number Example
random_odd = [Link](1, 100, 2)
➡ Generates random odd numbers less than 100.
random() Method
delay = [Link]()
Property Value
Output type Float
Interval [0.0, 1.0)
Distribution Uniform
Scaling Random Numbers
delay_in_seconds = [Link]() * 5.0
➡ Generates values in [0.0, 5.0).
Shuffling a List
cards = list(range(52))
[Link](cards)
Explanation
• range() → converted to list
• shuffle() rearranges elements randomly
• Used for card games, random sampling
8.1.1 Repeatability and Testing
Pseudo-Random Numbers
• Python random numbers are not truly random
• They are generated using a deterministic algorithm
2 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
• Hence called pseudo-random numbers
Seed Value
• Random number generators start with a seed
• Each generated number updates the internal state
• Same seed ⇒ same sequence of numbers
Why Repeatability is Important
Purpose Benefit
Debugging Same output every run
Unit Testing Predictable results
Program verification Easier error detection
Repeatability is useful only during testing, not in real gameplay or simulations.
Setting a Known Seed
import random
drng = [Link](123)
• 123 is the seed value
• Generator will produce the same random sequence every time
Example
import random
rng1 = [Link](42)
print([Link](1, 10))
print([Link](1, 10))
➡ Running this program multiple times produces the same output sequence.
Default Behavior (Without Seed)
• Python uses system time as seed
• Produces different results on each execution
8.1.2 Picking Balls from Bags, Throwing Dice, Shuffling Cards
1. Random Numbers With Replacement
(duplicates allowed)
• Same value can appear more than once
• Example: throwing a die multiple times
import random
3 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
def make_random_ints(num, lower, upper):
rng = [Link]()
result = []
for i in range(num):
[Link]([Link](lower, upper))
return result
Example
make_random_ints(5, 1, 13)
# Output: [8, 1, 8, 5, 6]
✔ Duplicates are allowed
Called sampling with replacement
2. Random Numbers Without Replacement
(no duplicates)
Shuffle and Slice Method
xs = list(range(1, 13))
rng = [Link]()
[Link](xs)
result = xs[:5]
✔ No duplicates
✔ Efficient for small ranges
Used in lottery games
3. Large Range Problem
Shuffle-and-slice is inefficient for very large ranges
Example: picking 5 numbers from 1 to 10,000,000
4. Without Replacement Using Checking
import random
def make_random_ints_no_dups(num, lower, upper):
result = []
rng = [Link]()
for i in range(num):
while True:
candidate = [Link](lower, upper)
4 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
if candidate not in result:
break
[Link](candidate)
return result
Example
make_random_ints_no_dups(5, 1, 10000000)
✔ Produces unique values
✔ Better than shuffling huge lists
5. Hidden Pitfall
make_random_ints_no_dups(10, 1, 6)
Infinite loop!
Why?
• Only 5 unique numbers possible (1–5)
• Program keeps searching for a new value forever
Rule
num ≤ (upper_bound - lower_bound)
Statistical Interpretation
Case Description
With duplicates Balls drawn with replacement
Without duplicates Balls drawn without replacement
Card Shuffling Example
cards = list(range(52))
[Link](cards)
✔ Simulates shuffling a deck of cards
8.2 The time Module
As programs become larger, it is important to measure execution time to evaluate [Link] provides
the time module to measure how long a program or function takes to run.
[Link]()
• Returns the elapsed CPU time in seconds since the program started.
• Used to compare the speed of different algorithms.
• Elapsed time = end time – start time
Measuring Execution Time – Method
5 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
1. Call clock() before the code → t0
2. Execute the code
3. Call clock() after the code → t1
4. Time taken = t1 - t0
Example: Comparing Custom Sum vs Built-in Sum
import time
def do_my_sum(xs):
total = 0
for v in xs:
total += v
return total
sz = 10000000
testdata = range(sz)
t0 = [Link]()
my_result = do_my_sum(testdata)
t1 = [Link]()
print("My sum time:", t1 - t0)
t2 = [Link]()
their_result = sum(testdata)
t3 = [Link]()
print("Built-in sum time:", t3 - t2)
Sample Output
My sum time ≈ 1.56 seconds
Built-in sum time ≈ 0.99 seconds
8.3 The math Module
The math module provides common mathematical functions and constants used in scientific and engineering
computations, similar to a calculator.
Important Mathematical Constants
import math
6 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
[Link] # 3.141592653589793
math.e # 2.718281828459045
• [Link] → Value of π
• math.e → Base of natural logarithm
Common Mathematical Functions
[Link](2.0) # Square root
[Link](10) # Natural logarithm
math.log10(100) # Base-10 logarithm
[Link]([Link](90)) # Trigonometric function
Angles: Radians vs Degrees
• Math functions use radians, not degrees
• Conversion functions:
[Link](90) # Converts degrees → radians
[Link]([Link]) # Converts radians → degrees
Trigonometric Example
[Link]([Link](90)) # Output: 1.0
[Link](1.0) * 2 # Output: π
Key Difference from random and turtle Modules
math module random / turtle
Stateless Stateful
Pure functions Methods on objects
No object creation Objects maintain state
• [Link](2) always returns the same result
• No internal state or history is maintained
8.4 Creating Your Own Modules
A module is simply a Python file (.py) that contains functions, variables, or classes which can be reused in
other programs.
Steps to Create a Module
1. Write Python code in a file
2. Save it with a .py extension
3. Import it using the import statement
Example: Creating a Module
7 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
File: [Link]
def remove_at(pos, seq):
return seq[:pos] + seq[pos+1:]
Using the Custom Module
import seqtools
s = "A string!"
seqtools.remove_at(4, s)
Output:
'A sting!'
Note:
• Do not include .py while importing
• Python automatically looks for .py files
Advantages of Creating Modules
• Improves code reuse
• Makes programs modular and readable
• Helps manage large programs
• Groups related functions together
8.5 Namespaces
A namespace is a collection of identifiers (names) such as variables, functions, and classes that belong to
a module, function, or class.
Namespaces help organize related names and prevent naming conflicts.
Module Namespace Example
[Link]
question = "What is the meaning of Life, the Universe, and Everything?"
answer = 42
[Link]
question = "What is your quest?"
answer = "To seek the holy grail."
Using Both Modules
import module1
import module2
print([Link])
8 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
print([Link])
print([Link])
print([Link])
Output
What is the meaning of Life, the Universe, and Everything?
What is your quest?
42
To seek the holy grail.
Same variable names do not conflict because each module has its own namespace.
Function Namespace Example
def f():
n=7
print("printing n inside of f:", n)
def g():
n = 42
print("printing n inside of g:", n)
n = 11
print("printing n before calling f:", n)
f()
print("printing n after calling f:", n)
g()
print("printing n after calling g:", n)
Output
printing n before calling f: 11
printing n inside of f: 7
printing n after calling f: 11
printing n inside of g: 42
printing n after calling g: 11
Variables with the same name exist independently in different namespaces.
9 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
Why Namespaces Are Important
• Avoid name collisions
• Support modular programming
• Allow multiple programmers to work safely
• Improve code clarity and organization
Relationship Between Namespace, Module, and File (Python)
Concept Description
File Physical storage on disk
Module Python code file (.py)
Namespace Logical grouping of names
In Python:
• One file → one module → one namespace
• Module name = file name (without .py)
Example:
[Link] → module math → namespace math
8.6 Scope and Lookup Rules
The scope of an identifier is the part of the program where that name can be accessed or used.
Types of Scope in Python
1. Local Scope
• Identifiers defined inside a function
• Exists only during function execution
• Each function has its own namespace
2. Global Scope
• Identifiers defined outside all functions
• Accessible throughout the module
3. Built-in Scope
• Names provided by Python by default
• Examples: range, len, min, max
Scope Lookup Rule (LEGB Rule )
When Python encounters a name, it looks in this order:
1. Local
10 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
2. Enclosing
3. Global
4. Built-in
Nearest (innermost) scope always takes precedence
Example 1: Hiding Built-in Names
def range(n):
return 123 * n
print(range(10))
Output
1230
Explanation
• User-defined range() is in global scope
• It overrides the built-in range()
• Global scope has higher priority than built-in scope
Redefining built-in names is discouraged
Example 2: Local vs Global Variables
n = 10
m=3
def f(n):
m=7
return 2 * n + m
print(f(5), n, m)
Output
17 10 3
Explanation
• Inside f(), n and m are local
• Outside f(), original n and m remain unchanged
• Local variables do not affect global variables
Visibility of Variables
11 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
• Global n is visible in:
o Lines outside the function
• Local n hides global n inside the function only
Built-in Inspection Functions
Function Purpose
locals() Shows local namespace
globals() Shows global namespace
dir() Lists names in current scope
x = 10 # Global
def outer():
x = 20 # Enclosing
def inner():
x = 30 # Local
print(x)
inner()
outer()
8.7 Attributes and the Dot Operator
Attributes
• Attributes are variables or functions defined inside a module or object.
• Any variable defined in a module becomes an attribute of that module.
Example:
# [Link]
question = "What is life?"
Accessing the attribute:
import module1
print([Link])
Dot Operator (.)
• The dot operator is used to access attributes of:
o Modules
o Objects
o Classes
12 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
Syntax
[Link]
[Link]
Accessing Functions Using Dot Operator
Modules can contain functions as well as variables.
import seqtools
seqtools.remove_at(4, "Python")
Here:
• remove_at is a function
• seqtools.remove_at is a fully qualified name
Object Attributes Example
def f():
"""Sample function"""
pass
print(f.__doc__)
✔ __doc__ is an attribute of the function object.
Fully Qualified Name
• A fully qualified name specifies exactly where a name comes from.
• It avoids ambiguity between identical names in different namespaces.
Examples:
• [Link]
• [Link]
• [Link]
8.8 Three Import Statement Variants
1. import module
import math
x = [Link](10)
Features
• Imports the module name only
• Access members using dot operator
• Avoids name conflicts
• Most recommended
13 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
✔ Clear
✔ Safe
✔ Preferred in exams and practice
2 from module import name1, name2
from math import cos, sin, sqrt
x = sqrt(10)
Features
• Imports specific names directly
• No need for dot operator
• Module name (math) is not available
⚠ Risk of name clashes
⚠ [Link]() will cause error
3 from module import *
from math import *
x = sqrt(10)
Features
• Imports all public names
• Short syntax, but unsafe
• Makes code hard to read and debug
Not recommended
Namespace pollution
Using Alias (as)
import math as m
print([Link])
Use Case
• Shortens module name
• Common in NumPy (import numpy as np)
Import Inside a Function (Local Import)
def area(radius):
import math
return [Link] * radius * radius
x = [Link](10) # Error
14 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
Explanation
• math is imported into local scope
• Not available in global scope
9.1 Mutable vs Immutable and Aliasing
Mutable Data Types
• Mutable objects can be changed after creation.
• Examples: list, dictionary, set
my_list = [2, 4, 5, 3, 6, 1]
my_list[0] = 9
print(my_list)
Output
[9, 4, 5, 3, 6, 1]
Immutable Data Types
• Immutable objects cannot be changed after creation.
• Examples: tuple, string, int, float
my_tuple = (2, 5, 3, 1)
my_tuple[0] = 9
Error
TypeError: 'tuple' object does not support item assignment
Aliasing
• Aliasing occurs when two variables refer to the same object in memory.
• Changing one variable affects the other.
list_one = [1, 2, 3, 4, 6]
list_two = list_one
list_two[-1] = 5
print(list_one)
Output
[1, 2, 3, 4, 5]
Verifying Aliasing using id()
id(list_one) == id(list_two)
Output
True
15 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
✔ Both variables point to the same memory location
Avoiding Aliasing (Shallow Copy)
list_one = [1, 2, 3, 4, 6]
list_two = list_one[:]
id(list_one) == id(list_two)
Output
False
✔ Now both lists are independent
Limitation of Shallow Copy
• Does not work for nested lists
• Inner lists are still shared
a = [[1, 2], [3, 4]]
b = a[:]
b[0][0] = 99
print(a)
Output
[[99, 2], [3, 4]]
Solution for Nested Structures
• Use deep copy
import copy
b = [Link](a)
11.1 Classes and Objects — The Basics
11.1.1 Object-Oriented Programming (OOP)
• Python is an object-oriented language.
• OOP focuses on objects that combine data (attributes) and behavior (methods).
• Developed to manage large and complex software systems.
• Earlier approach: Procedural programming (functions operate on data).
• OOP approach: Objects model real-world entities (e.g., Turtle, String, Random objects).
Example (real-world mapping):
• Object: Point
• Data: x, y coordinates
• Operations: distance, midpoint, location checks
11.1.2 User-Defined Compound Data Types
• Built-in classes: int, float, str, Turtle
• Users can define their own classes using class.
16 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
Example: Point Class
class Point:
"""Represents a point in 2D space"""
def __init__(self):
self.x = 0
self.y = 0
Key points:
• class keyword starts a class definition
• __init__() is the initializer method
• self refers to the current object
• Attributes x and y are created for each object
Creating Objects (Instantiation)
p = Point()
q = Point()
print(p.x, p.y, q.x, q.y)
Output
0000
• Each object has its own copy of attributes
• The process of creating and initializing objects is called instantiation
• Point() acts as a constructor
Class = factory, Object = product
11.1.3 Attributes
• Attributes are variables belonging to an object
• Accessed using the dot (.) operator
Modifying Attributes
p.x = 3
p.y = 4
Accessing Attributes
print(p.y)
x = p.x
Output
4
3
• p.x clearly means attribute x of object p
• Avoids name conflicts using fully qualified names
Using Attributes in Expressions
17 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
print("(x={0}, y={1})".format(p.x, p.y))
distance_squared = p.x*p.x + p.y*p.y
Output
(x=3, y=4)
distance_squared = 25
11.1.4 Improving our Initializer
Need for an Improved Initializer
Earlier, creating a point at (7, 6) required multiple statements:
p = Point()
p.x = 7
p.y = 6
Not convenient
More error-prone
Not expressive
Improved __init__() with Parameters
We improve the class by allowing x and y values during object creation.
class Point:
"""Point class represents and manipulates x,y coords."""
def __init__(self, x=0, y=0):
"""Create a new point at (x, y)"""
self.x = x
self.y = y
Key Features
• x and y are parameters
• Default values (x=0, y=0) make them optional
• Supports both:
o Creating a point at origin
o Creating a point at any location
Using the Improved Constructor
p = Point(4, 2)
q = Point(6, 3)
r = Point() # Defaults to (0, 0)
print(p.x, q.y, r.x)
Output
430
11.1.5 Adding Other Methods to Our Class
18 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
Why Add Methods to a Class?
• A class groups data and operations together
• Operations that are meaningful for a Point (like distance) should belong to the Point class
• This is better than using a tuple (x, y) where such operations are not naturally defined
Example:
• (6, 7) as a Point → distance calculation makes sense
• (25, 12) as (day, month) → distance makes no sense
Methods in a Class
• A method is a function defined inside a class
• It is called on an object
• Accessed using dot notation
• Always has self as the first parameter
Adding a Method: distance_from_origin
class Point:
"""Create a new Point at coordinates x, y"""
def __init__(self, x=0, y=0):
"""Create a new point at (x, y)"""
self.x = x
self.y = y
def distance_from_origin(self):
"""Compute distance from the origin"""
return ((self.x ** 2) + (self.y ** 2)) ** 0.5
Using the Method
p = Point(3, 4)
print(p.distance_from_origin())
Output
5.0
q = Point(5, 12)
print(q.distance_from_origin())
Output
13.0
19 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
r = Point()
print(r.distance_from_origin())
Output
0.0
11.1.6 Instances as Arguments and Parameters
Objects as Function Arguments
• Objects can be passed to functions just like numbers or strings
• The parameter receives a reference to the object, not a copy
• This creates aliasing: both the caller and function refer to the same object
Same concept was seen with turtle objects
Example: Passing a Point Object
def print_point(pt):
print("({0}, {1})".format(pt.x, pt.y))
• pt is a parameter
• It refers to the same Point object passed by the caller
Function Call
p = Point(3, 4)
print_point(p)
Output
(3, 4)
Key Observations
• p (caller) and pt (function parameter) are aliases
• There is only one Point object in memory
• Access to attributes is done using dot notation
Effect of Modifying Object Inside Function
def move_point(pt):
pt.x += 1
pt.y += 1
p = Point(3, 4)
move_point(p)
print(p.x, p.y)
20 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
Output
45
✔ Changes inside the function affect the original object
11.1.7 Converting an Instance to a String
Why Convert an Object to a String?
• Printing objects using print(obj) gives an unhelpful default output
• Example default output:
<__main__.Point object at 0x01F9AA10>
• This does not describe the object meaningfully
Naive Approach: Custom Print Method (Not Preferred)
def to_string(self):
return "({0}, {1})".format(self.x, self.y)
Usage:
print(p.to_string())
Not ideal because:
• Requires explicit method calls
• Does not integrate with print() or str()
Pythonic Solution: __str__() Method
• __str__() is a special (magic) method
• Automatically called by:
o str(object)
o print(object)
Correct Implementation
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return "({0}, {1})".format(self.x, self.y)
Usage
p = Point(3, 4)
21 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
print(p)
str(p)
Output
(3, 4)
11.1.8 Instances as Return Values
• In Python, functions and methods can return object instances, not just simple values.
• This allows creation of new objects as results of computations.
Using a Regular Function
• A function can take object instances as parameters, perform operations using their attributes, and
return a new instance.
def midpoint(p1, p2):
"""Return the midpoint of points p1 and p2"""
mx = (p1.x + p2.x) / 2
my = (p1.y + p2.y) / 2
return Point(mx, my)
Usage:
p = Point(3, 4)
q = Point(5, 12)
r = midpoint(p, q)
• Here, midpoint creates and returns a new Point object (4.0, 8.0).
Using a Method
• The same logic can be implemented as a method of the class, where one object acts on another.
class Point:
def halfway(self, target):
"""Return the halfway point between myself and the target"""
mx = (self.x + target.x) / 2
my = (self.y + target.y) / 2
return Point(mx, my)
Usage:
p = Point(3, 4)
q = Point(5, 12)
r = [Link](q)
Composability
22 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga
Python notes
• Object creation and method calls can be combined in a single expression:
print(Point(3, 4).halfway(Point(5, 12)))
11.1.9 A Change of Perspective (Object-Oriented View)
• In procedural programming, the function is the active agent.
Example:
print_time(current_time) → “Function, print this object.”
• In object-oriented programming (OOP), the object is the active agent.
Example:
current_time.print_time() → “Object, print yourself.”
• This style was already seen with turtles:
[Link](100) asks the turtle object to move itself.
• Shifting responsibility from functions to objects:
o Improves code reuse and maintainability
o Produces more flexible and modular programs
o Matches real-world thinking (behavior belongs to the object)
11.1.10 Objects Can Have State
• State refers to the data stored inside an object that can change over time.
• An object’s methods modify or use this state.
Examples:
• Turtle object
o State: position, direction, color, shape
o Methods: forward(), left() update its state
• Bank account object
o State: current balance, transaction history
o Methods: deposit(), withdraw(), get_balance(), show_transactions()
23 By,
Anusha Prima Fernandes, Asst. Professor, JNNCE Shivamogga