Lecture Note 5 - Modular Programming Note
Lecture Note 5 - Modular Programming Note
Modular Programming
1
v. Return Values: Functions can produce outputs by returning values.
This allows the result of the function’s computation to be used else-
where in the program.
xi. Scalability: As your project grows, functions allow you to scale your
codebase efficiently. Adding new features or extending existing ones
becomes more straightforward.
2
after the definition line. A docstring is a piece of string describing the
function and the task it performs.
ii. Keyword Arguments: These allow you to pass arguments using the
parameter’s name, which can be in any order. For example:
1 def greet(name, greeting):
2 return f"{greeting}, {name}!"
3 greet(greeting="Welcome", name="Eunice") #’Welcome,
Eunice!’
3
(b) Variable **kwargs allows a function to accept an arbitrary
number of keyword arguments. For example,
1 def display_info(**kwargs):
2 for key, value in [Link]():
3 print(f"{key}: {value}")
4
5 display_info(name="Segun", age=18, weight="67kg")
#
6 #name: Segun
7 #age: 18
8 #weight: 67kg
i. Single Value return: The function can return only one value.
1 def square(x):
2 return x ** 2
3
4 square(7) # 49
ii. Multiple Values return: The function can return multiple values in
a tuple which can be unpacked automatically.
1 def get_dimensions():
2 length = 10
3 width = 5
4 return length, width # Returns a tuple (10, 5)
5
4
iv. Return from Loops: a return statement can be used anywhere within
the function, including from inside a loop or conditional statements.
For example:
1 def find_even(numbers):
2 for num in numbers:
3 if num % 2 == 0:
4 return num # Returns the first even
number found
5 return None # If no even number is found
v. Early Return: Using return can be used for early exit from a func-
tion, which can make logic clearer in some cases.
1 def validate_password(password):
2 if len(password) < 8:
3 return False # Early return if condition not
met
4 # More checks here...
5 return True
5
iii. Anonymous Functions (Lambda Functions): Anonymous func-
tions, also known as lambda functions, are small, unnamed func-
tions defined with the lambda keyword. They are usually used for
short, simple operations that don’t require a formal function defini-
tion. They are useful when you need a short function for one time
use or when you want to pass a function as an argument to another
function without defining it separately. Here’s how they work:
1 lambda arguments: expression
• They can take any number of arguments but can only have one
expression.
• The expression is evaluated and returned when the lambda is
called.
• They are often used with functions like map(), filter(), and sorted()
6
• Changes to them to do not affect variables outside the function.
1.7 Modules
In Python, a module is a file that includes definitions, statements, func-
tions, classes, and variables. Programs are made easier to comprehend,
maintain, and reuse by the logical, manageable blocks of code that mod-
ules are intended to create. By dividing identifiers into distinct files so that
variables or functions with the same name do not conflict, modules help
prevent namespace pollution. Additionally, modules encourage code reuse
by enabling programmers to import and utilize the same functionality in
several apps without having to rewrite the code. Math, os, and sys are
just a few of the many built-in modules that come with Python. However,
developers may also construct their own custom modules by just saving
Python code in [Link] file. Larger applications can be even more structured
by grouping modules into packages, which are folders with several linked
modules.
Why Module in Python
7
1 # Create a simple module file named my_module.py
2 # my_module.py
3 def greet(name):
4 return f"Hello, {name}!"
5
6 PI = 3.14159
When a Python module is imported, the interpreter looks for it in the direc-
tories specified in [Link], which includes the installed third-party pack-
ages, built-in library locations, and the current working directory. After
the module is located, Python only runs it once-during the initial import-
and then saves the loaded module in memory to speed up subsequent im-
ports. The module [Link] notation, which maintains namespace orga-
nization and avoids naming conflicts, is used to access the module’s func-
tions, classes, and variables after import. To make commonly used module
names shorter and easier to work with, developers can also provide an alias
using the as keyword (import numpy as np, for example).
1 # [Link]
2 import my_module # Imports the entire module
3
4 print(my_module.greet("Student")) # Access via module name
5 print(my_module.PI) # Output: 3.14159
6
7 # With alias
8 import my_module as mm
9 print([Link]("Lecturer")) # Hello, Lecturer!
8
1.7.2 The from .. import Statement
This type of import removes the requirement to use the module name as
a prefix by bringing particular items-like functions, variables, or classes-
directly from a module into the current namespace of your application.
You can call sqrt() or date() directly without referring to [Link] or date-
[Link] by putting phrases like from math import sqrt or from datetime
import date. This can result in code that is clearer and more succinct,
particularly when utilizing only a few parts of a huge module. However,
because it avoids the module’s namespace, it raises the possibility of name
conflicts, in which imported names could take precedence over variables
or functions that are already present in your application. To preserve read-
ability and prevent unexpected behavior, this import style should be applied
carefully and deliberately.
1
2 from module_name import item1, item2, ... [as alias]
1. from module import ∗: All public names from a module are im-
ported straight into your namespace when you use from module im-
port *. Although eliminating prefixes can make code appear simpler,
it is usually discouraged because it becomes unclear which names
were defined locally and which came from the module. Addition-
ally, it makes debugging more difficult, decreases readability, and
raises the risk of name clashes, particularly in large applications. In-
teractive sessions and libraries that purposefully expose a narrow,
regulated public API are the primary contexts in which this style is
employed.
9
1 # [Link]
2 from my_module import greet, PI # Import specific items
3
4 print(greet("Student")) # No prefix needed
5 print(PI) # 3.14159
6
7 # With alias
8 from my_module import greet as hello
9 print(hello("Lecturer")) # Hello, Lecturer!
10
1 # [Link]
2 from my_module import * # Import everything
3
4 print(greet("Student")) # Hello, Student!
5 print(PI) # 3.14159
5 PI = 3.14159
6
7 if __name__ == "__main__":
8 print("Running as script!")
9 print(greet("Test User")) # Only runs when executed
directly
11
1.7.5 Introduction to Selected Packages in Python
Python offers a wide range of packages that go well beyond the language’s
basic functionality. Numerous helpful packages, such as modules for file
handling, math operations, working with dates, and networking, are in-
cluded into the standard library and can be used right away without requir-
ing installation. Furthermore, Python has an extensive library of third-party
packages that can be installed via pip and other similar tools. Data analy-
sis, scientific computing, machine learning, web development, automation,
and visualization are among the specific tasks that these extra programs
enable you to carry out. Writing effective, modular, and potent Python
programs requires an understanding of both standard and third-party pack-
ages. A few packages are included below, along with basic examples that
show what they can perform.
1 import random
2
3 print([Link](1, 10)) # Random int between 1-10
4 print([Link]([’apple’, ’banana’, ’cherry’])) #
Random fruit
1.8 Exercises
Q1: Write a function to calculate the area of a circle given its radius.
12
Q9: Write a decorator to log function calls.
Q10: Implement a decorator that times how long a function takes to run.
Q13: Use closures to create a function that keeps count of how many times
it has been called.
Q14: Write a function that returns another function which squares num-
bers but only if they are even.
13
14
Chapter 2
Python is naturally “object oriented”. In Python, objects are the data that
we have been associating with variables. Example
1 genes = ["AY342", "G54B"]
What the methods / functions are, how they work, and what the data are
(e.g., a list of numbers, dictionary of strings, etc.) are defined by a class:
the collection of code that serves as the “blueprint” for objects of that type
and how they work.
The class (much like the blueprint for a house) defines the structure of
objects, but each object’s instance variables may refer to different data el-
ements so long as they conform to the defined structure (much like how
different families may live in houses built from the same blueprint).
In Python, each piece of data we routinely encounter constitutes an object.
Each data type weâve dealt with so far (lists, strings, dictionaries, and so
on) has a class definition-a blueprint-that defines it. For example, lists have
data (numbers, strings, or any other type) and methods such as .sort()
and .append().
2.1 Inheritance
Inheritance allows a class (child class) to acquire the properties and meth-
ods of another class (parent class). This promotes code reusability and the
creation of hierarchical relationships between classes.
15
2.1.1 Key Characteristics
i. Reuse and extend the functionality of existing classes.
Basic Inheritance
Listing 2.1 shows the relationship between the Parent class which is a
base class or superclass and Child class which is the subclass or derived
class. The Parent class defines a greet method at line 2 that prints the
message ‘‘Hello from the Parent class" at line 3.
In line 5, the Child class is defined to inherit the Parent class. In line
6, the pass keyword keeps the class valid without a code to run under it.
Since the Child class has inherited the Parent class, it has access to the
method of the Parent class. In line 8, an object of the Child class is
created named child, and in line 9, the object called the greet method
of the Parent class has inherited.
1 class Parent:
2 def greet(self):
3 print("Hello from the Parent class!")
4
5 class Child(Parent):
6 pass
7
8 child = Child()
9 [Link]() # Output: Hello from the Parent class!
16
7 print("Hello from the Child class!")
8
9 child = Child()
10 [Link]() # Output: Hello from the Child class!
Multilevel Inheritance
As humans, we do not inherit information from our parents, we also inherit
information they inherit from their parents (our grandparents). The Child
class in Listing 2.3 inherits the Parent class in line 8 just as the Parent
class inherits the Grandparent class in line 5 as the Grandparent
class is defined in line 1. The child object is created in line 11 and it
calls the greet method of the Grandparent class inherited through
the Parent class.
1 class Grandparent:
2 def greet(self):
3 print("Hello from the Grandparent class!")
4
5 class Parent(Grandparent):
6 pass
7
8 class Child(Parent):
9 pass
10
11 child = Child()
12 [Link]() # Output: Hello from the Grandparent class!
1 class Animal:
2 def speak(self):
3 return "This animal makes a sound."
4
5 class Dog(Animal):
6 def speak(self):
7 return "Woof! Woof!"
8
9 # Using inheritance
10 generic_animal = Animal()
11 print(generic_animal.speak()) # Output: This animal makes
a sound.
12
13 pet = Dog()
14 print([Link]()) # Output: Woof! Woof!
17
Listing 2.4: Animal class and dog subclass example
2.2 Polymorphism
Polymorphism allows methods to perform different behaviours based on
the object it is acting upon. This is often achieved through method overrid-
ing or by using a common interface.
1 class Bird:
2 def fly(self):
3 return "Flying high."
4
5 class Penguin(Bird):
6 def fly(self):
7 return "I cannot fly but I can swim."
8
9 # Polymorphism in action
10 birds = [Bird(), Penguin()]
11 for bird in birds:
12 print([Link]())
13
14 # Output:
15 # Flying high.
16 # I cannot fly but I can swim.
18
8
9 class Cat(Animal):
10 def speak(self):
11 print("Meow")
12
10 def area(self):
11 return [Link] * [Link]
12
13 class Circle(Shape):
14 def __init__(self, radius):
15 [Link] = radius
16
17 def area(self):
18 return 3.14 * [Link] ** 2
19
20 shapes = [Rectangle(5, 10), Circle(7)]
21 for shape in shapes:
22 print([Link]())
23 # Output: 50
24 # 153.86
19
2.3 Data Abstraction
Data abstraction hides the implementation details and exposes only the
necessary functionality. Abstract classes or interfaces are often used to
achieve abstraction.
20
10 print("Bark")
11
12 class Cat(Animal):
13 def make_sound(self):
14 print("Meow")
15
16 animals = [Dog(), Cat()]
17 for animal in animals:
18 animal.make_sound()
19 # Output: Bark
20 # Meow
12 @property
13 def area(self):
14 return [Link] ** 2
15
16 square = Square(4)
17 print([Link]) # Output: 16
21
15 vehicle.start_engine()
16 # Output: Car engine started
17 # Bike engine started
2.4 Encapsulation
Encapsulation is one of the four fundamental Object-Oriented Program-
ming (OOP) concepts, along with inheritance, polymorphism, and abstrac-
tion. It refers to the concept of bundling data (attributes) and the methods
(functions) that operate on the data into a single unit called a class. Ad-
ditionally, encapsulation involves controlling access to the internal state of
an object, which is typically done using access modifiers.
Encapsulation in Python is a fundamental object-oriented programming
concept that restricts direct access to certain components of an object to
protect its internal state and ensure controlled modification. It helps in data
hiding and promotes the principle of modularity. Here’s how encapsulation
is implemented in Python:
1 class BankAccount:
2 def __init__(self, owner, balance):
3 [Link] = owner
4 self.__balance = balance # Private attribute
5
6 def deposit(self, amount):
7 self.__balance += amount
8
9 def withdraw(self, amount):
10 if amount <= self.__balance:
11 self.__balance -= amount
12 return amount
13 else:
14 return "Insufficient funds"
15
16 def get_balance(self):
17 return self.__balance
18
19 # Encapsulation in action
20 account = BankAccount("Alice", 1000)
21 [Link](500)
22 print(f"Balance after deposit: {account.get_balance()}") #
Output: Balance after deposit: 1500
23
24 print([Link](2000)) # Output: Insufficient funds
22
25 print(f"Balance after withdrawal: {account.get_balance()}")
# Output: Balance after withdrawal: 1500
23
Table 2.1: Public, Protected and Private Variables
Attribute Name Notation Behaviour
variable name, Public Can be accessed from inside
[Link] name and outside
variable name, Protected They are like a public mem-
self. variable name ber, but they are meant to be
accessed within the class and
its subclasses, but this is only
a convention, not a strict rule.
variable name, Private Private attributes and meth-
self. variable name ods are indicated with a dou-
ble underscore ( ). These
are accessible only within
the class where they are de-
fined. Python performs name
mangling to make private at-
tributes less accessible from
outside the class.
5 def display(self):
6 print(self._protected_data)
7
8 class SubClass(ProtectedExample):
24
9 def modify_protected_data(self, new_data):
10 self._protected_data = new_data
11
12 example = SubClass()
13 [Link]() # Output: This is protected data
14 example.modify_protected_data("Modified protected data")
15 [Link]() # Output: Modified protected data
Listing 2.6: I am
8 def display(self):
9 print(self.__private_data)
10 self.__private_method()
11
12 example = PrivateExample()
13 [Link]()
14 # Output: This is private data
15 # Accessing private method
16
17 # Direct access will raise an AttributeError:
18 # print(example.__private_data) # Uncommenting this line
will cause an error
19
20 # Private attributes can be accessed using name mangling:
21 print(example._PrivateExample__private_data) # Output:
This is private data
1 class Person:
2 def __init__(self, name):
3 self.__name = name # Private attribute
4
5 def get_name(self):
6 return self.__name
7
8 person = Person("Alice")
9 print(person.get_name()) # Output: Alice
25
1 class BankAccount:
2 def __init__(self):
3 self.__balance = 0
4
5 def deposit(self, amount):
6 if amount > 0:
7 self.__balance += amount
8
9 def get_balance(self):
10 return self.__balance
11
12 account = BankAccount()
13 [Link](100)
14 print(account.get_balance()) # Output: 100
14 @[Link]
15 def width(self, value):
16 if value > 0:
17 self.__width = value
18
19 rectangle = Rectangle(4, 5)
20 print([Link]) # Output: 20
21 [Link] = 10
22 print([Link]) # Output: 50
Q1: Implement a Person class with attributes like name, age, and meth-
ods to introduce themselves.
26
Q3: Design a Book class with title, author, and ISBN attributes, includ-
ing a method to display book info.
Q4: Create a class hierarchy for different types of vehicles (Car, Motor-
cycle, Bicycle) inheriting from a Vehicle base class.
Q7: Create a Car class where the speed can only be modified within a
safe range using getters and setters.
Q8: Use abc module to create an abstract base class Animal with an
abstract method sound, then implement it in subclasses.
Q11: Create a Vector class that supports vector addition and scalar mul-
tiplication using magic methods.
Q14: Create a mixin for logging capabilities that can be added to any class
for logging actions.
27
28
Chapter 3
File Processing
Python supports various file types for handling data, with each type de-
signed for specific use cases. The two primary categories are text files
and binary files, though there are specialized formats like CSV, JSON, and
others. Below are some of the important use cases of files operation in
Python.
1. File handling is vital for managing data storage and retrieval. Exam-
ples include:
The basic syntax for creating file in Python is shown in listing 3.1
29
1 file = open("[Link]", "mode")
2
30
• .txt files for plain text storage.
• .csv files for tabular data.
• .log files for logging activities.
• .json files for object serialization
31
3.1.3 CSV Files
CSV (Comma-Separated Values) files are commonly used for tabular data
storage. Pythonâs csv module provides methods for reading and writing
CSV files efficiently.
1 import csv
2
CSV files are extensively used in data analysis and machine learning, trans-
ferring tabular data between systems, and integrating with spreadsheet soft-
ware.
32
3.1.5 XML Files
XML (Extensible Markup Language) is another data format for storing
structured information. Pythonâs [Link] module
helps in parsing and generating XML.
1 import [Link] as ET
2
3 # Creating and writing to an XML file
4 data = [Link](’Data’)
5 item = [Link](data, ’Item’)
6 [Link] = ’Hello, XML!’
7 tree = [Link](data)
8 [Link](’[Link]’)
9
10 # Reading from an XML file
11 tree = [Link](’[Link]’)
12 root = [Link]()
13 for child in root:
14 print([Link], [Link])
Pickle files are used for saving Python objects like machine learning mod-
els or caching data.
33
Python’s ability to handle diverse file formats ensures its applicability across
industries, from web development to data science and machine learning.
The simplicity and power of Pythonâs file handling make it an indispens-
able tool for developers. Here are some areas where developers or pro-
grammers utilizes these files in the industries.
1. Data Processing: Text and CSV files are extensively used in data
analysis.
2. Web Development: JSON and XML are essential for web APIs and
configuration files.
4. Machine Learning: Pickle files save and load trained models effi-
ciently. There are other format like .hd5 or h5 in which ML models
can be saved.
34
Mode Description Example Code Application
’a’ Opens a file for append- file = Adding new content
ing at the end. Creates a open(’[Link]’, an existing file witho
new file if it doesnât ex- ’a’) modifying current co
ist. tent.
’b’ Opens a file in binary file = Working with non-te
mode. open(’[Link]’, files like images or e
’rb’) ecutables.
’t’ Opens a file in text file = Reading or writing te
mode (default). open(’[Link]’, files.
’rt’)
’+’ Opens a file for both file = Modifying files
reading and writing. open(’[Link]’, reading and writing.
’r+’)
’r+’ Opens a file for reading file = Reading and updating
and writing. File must open(’[Link]’, file’s content.
exist. ’r+’)
’w+’ Opens a file for reading file = Reading and writing
and writing. Creates a open(’[Link]’, a file while ensuri
new file if it doesnât ex- ’w+’) data is reset.
ist or truncates the file if
it exists.
’a+’ Opens a file for reading file = Reading and addi
and appending. Creates open(’[Link]’, content at the end o
a new file if it doesnât ’a+’) file.
exist.
’x+’ Opens a file for both file = Safely creating a
exclusive creation and open(’[Link]’, modifying new files.
reading/writing. Fails if ’x+’)
the file exists.
Python provides robust support for file handling, making it simple to read
from and write to files. In this section, we will explore different methods
and best practices for reading files effectively.
35
3.3.1 Methods for Reading Files
When working with files in Python, you can use the following methods to
read file content:
36
3.3.3 Handling Large Files Efficiently
Large files require careful handling to prevent memory issues. Here are
some strategies:
1. Process Line by Line Iterate through the file line by line to avoid
loading the entire content into memory:
1 with open(’large_file.txt’, ’r’) as file:
2 for line in file:
3 # Process each line
4 process_line(line)
37
explores these methods in detail and highlights key considerations.
This will create a file named [Link] with the specified content.
If the file does not exist, it will be created. The a mode ensures that
existing data remains intact while new data is added at the end.
38
1. Overwriting (w Mode) The w mode truncates the file to zero length
if it already exists, effectively deleting its content before writing new data.
Use this mode when you need to replace the entire file content.
1 with open(’[Link]’, ’w’) as file:
2 [Link](’New content\n’)
39
3.5.2 Benefits of Automatic File Closure
Using context managers for file handling provides several benefits:
40
2. Managing Large Files Efficiently The with statement is particularly
useful when handling large files, as it ensures proper memory management.
For instance:
1 with open(’large_file.txt’, ’r’) as file:
2 for chunk in iter(lambda: [Link](1024), ’’):
3 process_chunk(chunk)
41
2. PermissionError This occurs when the user does not have the re-
quired permissions to access or modify a file. Example:
1 with open(’/restricted_folder/[Link]’, ’w’) as file:
2 [Link](’Test’) # Raises PermissionError
This approach ensures that specific errors are addressed while other
exceptions are also captured for debugging.
42
1. Use the with Statement The with statement ensures that files are
automatically closed after operations, even if an error occurs:
1 with open(’[Link]’, ’r’) as file:
2 content = [Link]()
3 # File is automatically closed here
2. Validate File Paths Always check if the file path exists and is valid
using libraries like os:
1 import os
2
3 if [Link](’[Link]’):
4 print("File exists")
5 else:
6 print("File not found")
43
2. Normalize Line Endings Use the newline parameter when opening
files to handle line endings consistently:
1 with open(’[Link]’, ’r’, newline=’’) as file:
2 content = [Link]()
3.7 Exercises
Q1: Write a Python program to read a large text file line by line and
count the number of words in each line. Handle potential errors like
FileNotFoundError and PermissionError in the program.
Q3: Develop a script that appends a timestamped log message to a log file
every time it is executed. Use the datetime module to generate the
timestamp.
Q4: Create a Python program to merge the contents of multiple text files
into a single file. Ensure that each file’s content is separated by a
delimiter line (e.g., --- End of File 1 ---).
Q5: Develop a Python program that reads a CSV file from the user di-
rectory and writes only the rows with a specific condition (e.g., rows
where the second column value is greater than 100) to a new file.
Q6: Create a Python program that reads a binary file and outputs its hex-
adecimal representation. Ensure the output is formatted for user
readability.
Q7: Develop a program to compare two files line by line and print the
lines that differ. Additionally, write these differing lines to a separate
output file.
44
Q8: Create a program that backs up a directory by copying all its files
into a new folder. Use the os and shutil modules to handle file
and directory operations.
Q9: Write a script that reads a JSON file, modifies a specific key-value
pair, and writes the updated content back to the file. Handle errors
such as invalid JSON format.
Q11: Develop a program that reads a log file and extracts all lines contain-
ing a specific keyword (user-created keywords). Save these lines to
a separate file for further analysis.
Q12: Write a Python script to split a large text file into smaller files, each
containing a maximum of N lines. Allow the user to specify N.
Q13: Create a program that reads an XML file and converts it into a JSON
file. Ensure that the JSON structure reflects the hierarchy of the
XML.
Q15: Write a Python program to find and replace a specific word in a text
file. The program should allow the user to input the word to be re-
placed and its replacement. Save the updated content to a new file.
45
46
Bibliography
47
48
Bibliography
49
50
Glossary
51
52