0% found this document useful (0 votes)
61 views9 pages

Python Modules and Concepts Explained

The document covers various Python programming concepts including the use of random and time modules, namespaces, class vs instance attributes, module creation, and the difference between 'is' and '==' operators. It provides example programs demonstrating a stopwatch simulation, variable lookup using the LEGB rule, and functions for mathematical operations like square, cube, and factorial. Additionally, it explains the concept of binomial coefficients and immutability in Python.

Uploaded by

Basavaraj C
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
61 views9 pages

Python Modules and Concepts Explained

The document covers various Python programming concepts including the use of random and time modules, namespaces, class vs instance attributes, module creation, and the difference between 'is' and '==' operators. It provides example programs demonstrating a stopwatch simulation, variable lookup using the LEGB rule, and functions for mathematical operations like square, cube, and factorial. Additionally, it explains the concept of binomial coefficients and immutability in Python.

Uploaded by

Basavaraj C
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

1BPLC105B Introduction to Python

Module-4
Q1) Explain the use of random and time modules in Python. Develop a program that
simulates a simple stopwatch that records random time intervals and calculates the average
elapsed time.

Ans: 1. Random Module: The random module is used to generate pseudo-random


numbers in Python.
 [Link]() → float between 0.0 and 1.0
import random
random_float = [Link]()
print(random_float)
 [Link](a, b) → integer between a and b (inclusive)
import random
randomint = [Link](10,50)
print(randomint)
 [Link](a, b) → float between a and b
import random
randomint = [Link](10,50)
print(randomint)
2. Time Module: The time module provides functions to work with time-related tasks.
Common functions:

 [Link]() → current time in seconds since the epoch


import time
t=[Link]()
print(t)
 [Link](): display current time in human readable format
import time
t=[Link]()
print(t)
start = time.perf_counter()

 [Link](seconds) → pause execution for given seconds

import time

Basavaraj C Asst. Prof, LAEC,Bidar Page 1


1BPLC105B Introduction to Python

print(“ hello”)
[Link](10)
print(“fine”)
 time.perf_counter() → high-resolution timer for measuring elapsed time
import time
start = time.perf_counter()
print(start)

Program
import time
import random

def simulate_stopwatch(trials=5):
if trials <= 0:
raise ValueError("Number of trials must be positive.")

elapsed_times = []

print("Stopwatch simulation started...\n")


for i in range(1, trials + 1):
wait_time = [Link](1, 5)
print(f"Trial {i}: Waiting for {wait_time:.2f} seconds...")

start = time.perf_counter() # Start stopwatch


[Link](wait_time) # Simulate elapsed time
end = time.perf_counter() # Stop stopwatch

elapsed = end - start


elapsed_times.append(elapsed)
print(f"Trial {i} elapsed time: {elapsed:.2f} seconds\n")

avg_time = sum(elapsed_times) / len(elapsed_times)


print(f"Average elapsed time over {trials} trials: {avg_time:.2f} seconds")
if __name__ == "__main__":
try:
simulate_stopwatch(trials=5)
except ValueError as e:
print(f"Error: {e}")

Basavaraj C Asst. Prof, LAEC,Bidar Page 2


1BPLC105B Introduction to Python

Q2 ) Explain the concept of namespaces in Python. Develop program to illustrate how


variable lookup follows the LEGB (Local, Enclosing, Global, Built-in) rule.

Ans 2: Namespaces in Python: A namespace in Python is a mapping between names


(identifiers) and objects. It ensures that names are unique and can be used without conflict.

Types of Namespaces

1. Built-in Namespace
o Contains names of Python’s built-in functions and exceptions (len, print,
ValueError, etc.).
o Available everywhere in Python.
2. Global Namespace
o Contains names defined at the top level of a module or script.
o Each module has its own global namespace.
3. Enclosing Namespace
o Exists in nested functions.
o Contains names from the outer (non-global) function.
4. Local Namespace
o Contains names defined inside a function.
o Created when the function is called and destroyed when it returns.

LEGB Rule: When Python encounters a variable name, it searches in the following order:

1. Local → Inside the current function.


2. Enclosing → In the outer function(s) if nested.
3. Global → At the top level of the current module.
4. Built-in → In Python’s built-in namespace.

Example Program: LEGB Rule in Action

Python

# Global variable
x = "global x"

def outer_function():
# Enclosing variable
x = "enclosing x"

def inner_function():
# Local variable
x = "local x"
print("Inside inner_function:", x) # Local scope

def inner_no_local():
# No local 'x', so Python looks in enclosing scope
print("Inside inner_no_local:", x) # Enclosing scope

Basavaraj C Asst. Prof, LAEC,Bidar Page 3


1BPLC105B Introduction to Python

inner_function()
inner_no_local()

def global_lookup():
# No local or enclosing 'x', so Python looks in global scope
print("Inside global_lookup:", x)

def built_in_lookup():
# Example: using built-in 'len'
sample_list = [1, 2, 3]
print("Length using built-in len():", len(sample_list))

# Run the functions


outer_function()
global_lookup()
built_in_lookup()

Q3) Differentiate between class attribute and instance attribute with suitable program
segments.

What is Class Attributes: In object-oriented programming (OOP), a class is a blueprint for


creating objects, and class attributes are variables that are associated with a class , Class
attributes are shared among all instances of a class and are defined within the class itself.

class MyClass:
Pi=3.142
print([Link])
In above example Pi is Class attribute

What is Instance Attributes: Instance attributes in object-oriented programming (OOP)


are variables that belong to an instance of a class. Unlike class attributes, which are shared
among all instances of a class, each instance attribute is specific to a particular object
created from that class. These attributes define the characteristics or properties of individual
objects.
class Car:
def __init__(self, brand, model):
[Link] = brand
[Link] = model
car1 = Car(&quot;Toyota&quot;, &quot;Camry&quot;)
car2 = Car(&quot;Honda&quot;, &quot;Civic&quot;)

print(f&quot;{[Link]} {[Link]}&quot;)
print(f&quot;{[Link]} {[Link]}&quot;)

In above program the brand and model are the Instance attribute.

Basavaraj C Asst. Prof, LAEC,Bidar Page 4


1BPLC105B Introduction to Python

Q4) Develop python script to create a module [Link] with functions for square,
cube, and factorial of a number. Import it in another file using all three import
variants. Demonstrates the usage of each of the imported function.

Ans:

1. Module: [Link]

Python

def square(n):
return n * n

def cube(n):
return n * n * n

def factorial(n):

if n < 0:
raise ValueError("factorial() not defined for negative numbers")
result = 1
for i in range(2, n + 1):
result *= i
return result

2. Main Script: [Link]

Python

# 1️⃣ Import the whole module


import utilities

# 2️⃣ Import specific function


from utilities import cube

# 3️⃣ Import all functions (not recommended in large projects)


from utilities import *

import utilities

def main():
num = 5

# Using full module reference


print(f"Square of {num} (import utilities): {[Link](num)}")

Basavaraj C Asst. Prof, LAEC,Bidar Page 5


1BPLC105B Introduction to Python

# Using directly imported function


print(f"Cube of {num} (from utilities import cube): {cube(num)}")

# Using wildcard import


print(f"Factorial of {num} (from utilities import *): {factorial(num)}")

if __name__ == "__main__":
main()

How to Run

1. Save [Link] and [Link] in the same folder.


2. Run:

Bash

python [Link]

Q5) Develop a custom module having function which calculates factorial of a number.
Import this custom module to a program to calculate binomial coefficient.

Ans:

(nr)=n!r!⋅(n−r)!\binom{n}{r} = \frac{n!}{r! \cdot (n-r)!}(rn)=r!⋅(n−r)!n!

Step 1: Create the custom module

Save the following code as [Link]:

Python

def factorial(n):
if not isinstance(n, int):
raise TypeError("Factorial is only defined for integers.")
if n < 0:
raise ValueError("Factorial is not defined for negative numbers.")
result = 1
for i in range(2, n + 1):
result *= i
return result

Step 2: Main program to calculate binomial coefficient

Basavaraj C Asst. Prof, LAEC,Bidar Page 6


1BPLC105B Introduction to Python

Save this as [Link] in the same folder as [Link]:

Python

# [Link]
"""
Program to calculate binomial coefficient using custom factorial module.
"""

import mymath # Import our custom module

def binomial_coefficient(n, r):


"""
Calculate binomial coefficient C(n, r) using factorial from mymath module.
"""
if not (isinstance(n, int) and isinstance(r, int)):
raise TypeError("n and r must be integers.")
if r < 0 or n < 0:
raise ValueError("n and r must be non-negative.")
if r > n:
raise ValueError("r cannot be greater than n.")

return [Link](n) // ([Link](r) * [Link](n - r))

if __name__ == "__main__":
try:
n = int(input("Enter n (non-negative integer): "))
r = int(input("Enter r (non-negative integer): "))
result = binomial_coefficient(n, r)
print(f"C({n}, {r}) = {result}")
except Exception as e:
print("Error:", e)

Q6) Explain the difference between ‘is’ and ‘==’ operators using immutable objects.

Ans : In Python, is and == compare different things—even when you’re working with
immutable objects (like integers, strings, or tuples).
== → Value equality
 Checks whether two objects have the same value
 Calls the object’s __eq__() method

Basavaraj C Asst. Prof, LAEC,Bidar Page 7


1BPLC105B Introduction to Python

a = 1000
b = 1000
print(a == b) # True
Even if a and b are different objects in memory, == is True because their values are equal.

is → Identity (same object in memory)


 Checks whether two variables refer to the exact same object
 Compares memory identity, not value
print(a is b) # False (usually)
Here, a and b may store the same value, but they are different objects.
Why immutability matters
Immutable objects cannot be changed after creation, so Python sometimes reuses objects
for efficiency (called interning).
Example with small integers:
x = 10
y = 10
print(x == y) # True
print(x is y) # True
Python caches small integers (typically -5 to 256), so both variables point to the same object.
Example with strings:
s1 = "hello"
s2 = "hello"
print(s1 == s2) # True
print(s1 is s2) # True (often, due to string interning)
But:
s3 = "".join(["he", "llo"])
print(s1 == s3) # True
print(s1 is s3) # False
Same value, different objects.
Key takeaway
Operator What it compares Use case
== Values are equal Almost always what you want
is Same object in memory Checking identity (e.g., None)

Basavaraj C Asst. Prof, LAEC,Bidar Page 8


1BPLC105B Introduction to Python

Basavaraj C Asst. Prof, LAEC,Bidar Page 9

Common questions

Powered by AI

Namespaces in Python, which are mappings from names to objects, provide organizational structure to avoid naming conflicts . The LEGB rule determines variable lookup by searching in the order of Local (within the function), Enclosing (outer functions), Global (top-level module), and Built-in (Python's core functions). Understanding namespaces is vital as it ensures the correct variable is accessed in diverse scopes, especially with nested functions, where different variables may have the same name but reside in distinct namespaces. This hierarchical search order maintains clarity and scope integrity, preventing name collision and logic errors in complex applications .

Understanding Python's namespace concept is essential because it clarifies how and where different identifiers are stored and accessed in code, enabling precise scope management and conflict avoidance, especially in larger applications . It facilitates real-time name resolution using LEGB rules for logical consistency when accessing variables, where local, enclosing, global, and built-in scopes are checked systematically . This understanding allows developers to purposefully design more robust systems, where modularity and encapsulation prevent unintended side effects, significantly enhancing code maintainability and scalability in complex systems .

To calculate a binomial coefficient utilizing a custom module, one must first create a module (e.g., mymath.py) with a factorial function that accurately computes factorials of non-negative integers . The main program (e.g., binomial.py) imports this module and then defines a function to compute the binomial coefficient using the formula C(n, r) = n! / (r! * (n-r)!). The program calls mymath.factorial for each factorial component in the formula to ensure modular and efficient computation. Illustrating input validation is key here to prevent computation errors, especially when n < r or variables are non-integers .

The '==' operator checks for value equality, meaning it evaluates whether two objects have equivalent values, which is typical for most use cases . Conversely, the 'is' operator checks for identity, determining if two references point to the exact same object in memory . For immutable objects, Python might reuse objects (interning), so 'is' can sometimes return True for seemingly identical objects due to optimization strategies . These differences impact memory usage, as multiple references might point to a single object, reducing overhead. However, using 'is' for value checks might lead to false conclusions if objects are different but logically equivalent, highlighting the importance of choosing the correct operator for specific needs .

Choosing between 'is' and '==' in Python depends on whether one wants to compare objects for identity or equivalence of value. '==' checks if the values held by objects are equal, while 'is' checks if both variables point to the very same object in memory . Immutability means objects cannot be altered post-creation, which often leads Python to reuse immutable object instances, such as small integers or interned strings, for memory efficiency . This can result in faster comparisons using 'is'. However, relying on 'is' for value comparisons can yield incorrect results if different memory allocations occur, making '==' more applicable for value-based logic .

Creating a Python module supports modular programming by encapsulating related functions and logic into reusable components, promoting code reuse and separation of concerns . Import variants provide different levels of control over the namespace and dependencies: importing entire modules maintains the module scope, importing specific functions reduces namespace pollution, and wildcard imports maximize convenience albeit at the risk of conflicts . For large codebases, these strategies enable structured dependency management and prevent name collision, thus ensuring that components are adaptable, maintainable, and interconnected without undue complexity or error propagation .

Class attributes are associated with the class itself, shared among all instances, and defined when the class is defined . Instance attributes belong to specific objects created from the class, unique to each instance, and are typically defined within the class's __init__ method . Class attributes enable shared data or behavior across all instances, whereas instance attributes allow for individual customization and data storage per object instance. This distinction allows for more flexible object-oriented design, where default behaviors can coexist with instance-level specificities .

The LEGB rule manages variable scope by searching for variable names within a specific sequence: Local (inside the function), Enclosing (outer non-global functions), Global (top-level of the module), and Built-in (Python's standard library). In nested functions, this hierarchy determines variable accessibility and resolution, allowing each function scope to override the enclosing or global scope without affecting others. As such, variables inside an inner function can shadow those of enclosing scopes, leading to greater flexibility and control over data encapsulation, which is especially significant in closures or decorators where persistent state management is critical .

The random module in Python is used for generating pseudo-random numbers, with functions like random.random() for a float between 0.0 and 1.0, random.randint(a, b) for an integer between a and b, and random.uniform(a, b) for a float between a and b . The time module provides functions for time-related tasks, such as time.time() for the current time in seconds since the epoch and time.perf_counter() for a high-resolution timer . To simulate a stopwatch, a function can utilize random.uniform(1, 5) to generate random wait times and time.sleep to pause execution, while time.perf_counter() is used to measure the elapsed time between start and end time points. By averaging the elapsed times over multiple trials, the program calculates the average elapsed time .

A Python module can be created by defining functions such as square, cube, and factorial in a file named utilities.py . This module can be imported into another script using different variants: by importing the whole module with import utilities and accessing functions with utilities.function_name(); by importing specific functions with from utilities import function_name and calling them directly; or by importing all module functions with from utilities import * (not recommended for larger projects due to potential namespace conflicts). Each approach offers different levels of scope control and namespace management .

You might also like