0% found this document useful (0 votes)
5 views52 pages

Lecture Note 5 - Modular Programming Note

Chapter 1 covers the fundamentals of modular programming in Python, emphasizing the importance of functions for code organization, reusability, and maintainability. It explains how to define functions, the different types of parameters, return statements, and the types of functions including built-in, user-defined, and anonymous functions. Additionally, the chapter discusses the concept of modules, their benefits, and various import statements to manage namespaces effectively.

Uploaded by

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

Lecture Note 5 - Modular Programming Note

Chapter 1 covers the fundamentals of modular programming in Python, emphasizing the importance of functions for code organization, reusability, and maintainability. It explains how to define functions, the different types of parameters, return statements, and the types of functions including built-in, user-defined, and anonymous functions. Additionally, the chapter discusses the concept of modules, their benefits, and various import statements to manage namespaces effectively.

Uploaded by

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

Chapter 1

Modular Programming

1.1 Basic Concept of modular programming


1.1.1 What are Functions?
A function in Python is a reusable block of code that performs a specific
task. It allows you to encapsulate a piece of logic that can be executed
multiple times within your program without rewriting the code each time.

1.1.2 Why function


Function is a good choice for the following reasons.

i. Encapsulation: Functions help in organising code by wrapping it


into a named block. This makes programs more modular and easier
to maintain.

ii. Reusability: Once defined, a function can be called multiple times


with different arguments, saving time and reducing errors from code
duplication.

iii. Abstraction: Functions hide the complexity of an operation behind


a simple interface. This means the user of the function only needs to
know what the function does, not how it does it.

iv. Parameter Passing: Functions can take parameters (inputs) which


are used to perform operations within the function. This allows the
function to work with different data each time it’s called.

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.

vi. Modularity: Functions break down complex problems into smaller,


manageable pieces. This modular approach simplifies development,
debugging, and maintenance of code.

vii. Readability: Functions make code more readable by giving mean-


ingful names to blocks of code. This self-documentation aspect
makes it easier for others (or yourself in the future) to understand
what the code does at a glance.

viii. Maintainability: If there’s a change to be made in how something


is done, you only need to update the function rather than every in-
stance where that code might appear. This centralizes changes and
simplifies maintenance.

ix. Namespace Isolation: Variables inside functions (local variables)


don’t interfere with global variables or variables in other functions,
which helps prevent naming conflicts and makes the code cleaner.

x. Testing and Debugging: Functions can be tested in isolation, which


is a key practice in unit testing. It’s easier to pinpoint errors when
each function handles a specific task.

xi. Scalability: As your project grows, functions allow you to scale your
codebase efficiently. Adding new features or extending existing ones
becomes more straightforward.

xii. Functional Programming Paradigms: Python supports functional


programming concepts, where functions can be treated like any other
object. This opens up possibilities like higher-order functions, which
are functions that can take other functions as arguments or return
functions.

1.2 Defining Functions


A function can be defined by using the def keyword, follow by the func-
tion name and optional parameters in parenthesis and lastly the colon.
Additionally, and for good programming habbit, a docstring is inserted

2
after the definition line. A docstring is a piece of string describing the
function and the task it performs.

1.3 Function Parameters


Parameters are variables listed in the function definition’s parentheses. They
act as placeholders for the values that will be passed to the function when
it’s called.
These are the types of parameter.
i. Positional Parameters: These are matched by position in the func-
tion call. The order of arguments must match the order of parameters
in the function definition. For example:
1 def greet(name, greeting):
2 return f"{greeting}, {name}!"
3 greet("Isaac", "greetings") # ’greetings, Isaac!’

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!’

iii. Default Parameters: If a parameter has a default value, you can


omit that argument when calling the function, and it will use the
default. For example:
1 def greet(name, greeting="Hello"):
2 return f"{greeting}, {name}!"
3 greet("Eunice") #’Hello, Eunice!’

iv. Variable Length Arguments:


(a) Variable *args allows a function to accept an arbitrary num-
ber of positional arguments. For example,
1 def sum_all(*args):
2 return sum(args)
3
4 sum_all(1,2,6,8) # 17
5

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

1.4 Return Statement


The return keyword is used to exit a function and go back to the place
from where it was called, optionally passing back an expression’s value.
Here are some key points:

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

6 l, w = get_dimensions() # Unpacks to l=10, w=5

iii. No Return value: if there is no return statement, Python returns


None.
1 def greet(name):
2 print(f"Hello, {name}!") # No return statement,
returns None

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

1.5 Types of Functions


There are three types of functions. Built-in functions, user defined func-
tions and anonymous functions.

1. Built-in functions: This are functions that included in Python by


default and do not need to be imported. E.g.

• print(): Outputs text to the console.


• len(): Returns the length of an object (e.g., string, list).
• sum(): Sums up the elements of an iterable.
• range(): Generates a sequence of numbers.
• type(): Returns the type of an object.

ii. User-Defined Functions: User-defined functions are functions that


you, the programmer, create to perform specific tasks. They are de-
fined using the def keyword.

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()

1 # Using lambda with sorted() to sort a list of tuples


by the second element
2 pairs = [(1, ’one’), (3, ’three’), (2, ’two’)]
3 sorted_pairs = sorted(pairs, key=lambda x: x[1])
4 print(sorted_pairs) # Output: [(1, ’one’), (3, ’three
’), (2, ’two’)]
5
6 # Using lambda with map() to square each element in a
list
7 numbers = [1, 2, 3, 4]
8 squared_numbers = list(map(lambda x: x**2, numbers))
9 print(squared_numbers) # Output: [1, 4, 9, 16]

1.6 Scope of functions


In Python Programming, the variables inside a function is called local vari-
ables while global variables are variables defined outside of any function,
at the script or module level, making them accessible throughout the entire
script or module.
i. Characteristics of Local variable

• They are only visible and accessible in the function.


• They have the same life time as the function.

6
• Changes to them to do not affect variables outside the function.

i. Characteristics of global variable

• They are visible anywhere in the script or module.


• They share the same lifetime with the script or module.
• to modify a global variable inside a function, you must use the
keyword global to indicate you are working with the global
variable.

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

1. Modularity: Break large programs into smaller files.

2. Reusability: Import pre-written code (e.g., standard libraries like


math).

3. Namespace Management: Avoid variable/function name conflicts.

4. Standard Library: Python comes with hundreds of built-in modules


(e.g., os, sys).

5. Third-Party: Install via pip (e.g., numpy, pandas).

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

1.7.1 Import statement


In Python, a whole module can be loaded into your program using the
import statement, giving you access to its defined variables, classes, and
functions. When a module is imported, Python makes its contents available
under the module’s namespace and runs the module’s code once. To min-
imize naming conflicts and maintain code organization, the module name
must be used as a prefix when accessing elements from the module. As an
example:
1
2 import module_name [as alias]

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.

2. Import Aliasing: By using aliasing, you can import a module and


give it a more easy or concise name. For modules with lengthy names
or those commonly used in scientific computing, such as numpy ß np
and pandas ß pd, this is particularly useful. Aliasing enhances read-
ability, minimizes typing effort, and adheres to standard community
conventions, increasing the consistency of your code with generally
accepted techniques.

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!

1.7.3 The from .. import * Statement


All public names from a module are imported straight into the current
namespace using the from module import * statement. Names that don’t
start with an underscore ( ) are considered public. This statement brings all
of the module’s available functions, classes, and variables into your appli-
cation without requiring the module name to be used as a prefix. Although
this can make the code seem shorter, it obscures the origins of each name,
which can cause name conflicts and make debugging more challenging.
It is usually avoided in production code since it shadows or overrides ex-
isting variables without warning. namespace safety, maintainability, and
adaptability.
1
2 from module_name import *

In essence, using from module import * is the same as explicitly importing


each public name from a module without the need to list each one sepa-
rately. Leading underscores indicate that an item is intended to be private
or internal to the module, therefore only items that don’t start with one
(like private var) are imported. But if the module defines a unique list
called all (e.g., all = [’item1’, ’item2’]); Python will import only
the names in that list, whether or not they have underscores. When im-
port * is used, this method allows module developers to precisely control
what is exported. It is generally advised to avoid this import style in big-
ger applications since, although this feature can make it easier to access a
module’s contents, it also raises the risk of namespace pollution and makes
it more difficult to track the origin of names.

10
1 # [Link]
2 from my_module import * # Import everything
3
4 print(greet("Student")) # Hello, Student!
5 print(PI) # 3.14159

1.7.4 Executing Modules as Scripts


A module in Python can be used directly as a standalone script or it can be
imported by other programs to reuse its classes and functions. Python sets
a unique built-in variable called name when you launch a module using
a command like python my [Link]. Python sets name = ” main ”
when the module is executed as the main program. Nevertheless, the value
of name becomes the module’s real filename (without [Link] extension)
when the same file is imported into a different module. You can design
modules that act differently based on how they are used thanks to this tech-
nology. If you put specific code inside an if name == ” main ”:
block, you can make sure that it only runs when the module is executed
directly and not when it is imported. This is helpful for adding tests, use
examples, demo code, or command-line functionality without interfering
with programs that only import the module.
updating the [Link]
1 # my_module.py
2 def greet(name):
3 return f"Hello, {name}!"
4

5 PI = 3.14159
6
7 if __name__ == "__main__":
8 print("Running as script!")
9 print(greet("Test User")) # Only runs when executed
directly

importing the module


1 # [Link]
2 import my_module # No "Running as script!" printed
3 print(my_module.PI) # Works fine

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.

Q2: Create a function that returns the absolute value of a number.

Q3: Define a function that converts Celsius to Fahrenheit.

Q4: Write a recursive function to calculate the sum of numbers from 1 to


n.

Q5: Implement a recursive function to compute the nth Fibonacci num-


ber.

Q6: Create a recursive function to reverse a string.

Q7: Write a function that returns a multiplier function.

Q8: Create a closure to generate a sequence of numbers starting from a


given number.

12
Q9: Write a decorator to log function calls.

Q10: Implement a decorator that times how long a function takes to run.

Q11: Create a decorator that repeats a function a specified number of times.

Q12: Combine recursion and decorators: Write a decorator to count how


many times a recursive function has been called.

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.

Q15: Implement a recursive function with a decorator that checks if the


input is positive before proceeding.

13
14
Chapter 2

Modular Programming (contd.

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.

ii. Establish parent-child relationships.

iii. Reduces redundancy.

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!

Listing 2.1: Example of Basic Parent and Child class


Overriding Methods
In Listing 2.2, the Child class inherited the Parent class but overrides
the greet method of the Parent class by implementing its own greet
method. When the child object calls the greet method, it calls the greet
method of the Child class rather than that of the Parent class because
it has overridden it.
1 class Parent:
2 def greet(self):
3 print("Hello from the Parent class!")
4
5 class Child(Parent):
6 def greet(self):

16
7 print("Hello from the Child class!")
8
9 child = Child()
10 [Link]() # Output: Hello from the Child class!

Listing 2.2: Example of Inheritance with overriding Methods

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!

Listing 2.3: Child class inherits from the Grandparent

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.

2.2.1 Key Characteristics


i. Methods or functions operate on objects of different classes.

ii. Supports dynamic method resolution.

iii. Promotes flexibility and reusability.

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.

Example: Method Overriding


1 class Animal:
2 def speak(self):
3 print("The animal makes a sound")
4
5 class Dog(Animal):
6 def speak(self):
7 print("Bark")

18
8
9 class Cat(Animal):
10 def speak(self):
11 print("Meow")
12

13 animals = [Dog(), Cat()]


14 for animal in animals:
15 [Link]()
16 # Output: Bark
17 # Meow

Example: Function Overloading (Using Default Arguments in Python)


1 def add(a, b=0):
2 return a + b
3
4 print(add(2)) # Output: 2
5 print(add(2, 3)) # Output: 5

Example: Polymorphism with Common Interface


1 class Shape:
2 def area(self):
3 pass
4
5 class Rectangle(Shape):
6 def __init__(self, width, height):
7 [Link] = width
8 [Link] = height
9

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.

2.3.1 Key Characteristics


i. Focuses on what an object does rather than how it does it.

ii. Simplifies complex systems by reducing details.

1 from abc import ABC, abstractmethod


2
3 class Shape(ABC):
4 @abstractmethod
5 def area(self):
6 pass
7
8 class Rectangle(Shape):
9 def __init__(self, width, height):
10 [Link] = width
11 [Link] = height
12
13 def area(self):
14 return [Link] * [Link]
15
16 # Abstracting the concept of a shape
17 rect = Rectangle(10, 5)
18 print(f"The area of the rectangle is: {[Link]()}")
19
20 # Output:
21 # The area of the rectangle is: 50

Example: Using Abstract Base Classes


1 from abc import ABC, abstractmethod
2
3 class Animal(ABC):
4 @abstractmethod
5 def make_sound(self):
6 pass
7
8 class Dog(Animal):
9 def make_sound(self):

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

Example: Abstract Properties


1 from abc import ABC, abstractmethod
2
3 class Shape(ABC):
4 @abstractmethod
5 def area(self):
6 pass
7
8 class Square(Shape):
9 def __init__(self, side):
10 [Link] = side
11

12 @property
13 def area(self):
14 return [Link] ** 2
15
16 square = Square(4)
17 print([Link]) # Output: 16

Example: Interface Example


1 class Vehicle:
2 def start_engine(self):
3 pass
4
5 class Car(Vehicle):
6 def start_engine(self):
7 print("Car engine started")
8
9 class Bike(Vehicle):
10 def start_engine(self):
11 print("Bike engine started")
12
13 vehicles = [Car(), Bike()]
14 for vehicle in vehicles:

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

Listing 2.5: Bank Account Class


The bankAccount class in Listing 2.5 has two class attributes a public
owner and a private balance because the name of an account can be
public, but the balance of the account must be private. An object account
of the class was created in line 20 with the owner parameter as ”Alice”
and the balance parameter as 1000. In line 21, the deposit method
of the account object is called with parameter amount as 500 to add to
the balance parameter which has been set to 1000 and the balance
becomes 1500. In line 24, the withdraw method of the account object
is called and 2000 is supplied for the amount parameter. Remember that
Python supplies the self parameter in a method.
There is another way called protected in which attributes are presented a
class. This coupled with private and public is discussed in the next subsec-
tion.

2.4.1 Public, Protected and Private Variables


In Python, access modifiers are used to define the visibility of class at-
tributes and methods. Python uses naming conventions to indicate the level
of access, as it does not enforce strict access control like some other lan-
guages (e.g., Java or C++).
The Table 2.1 shows the different behaviour public, protected and private
variables.

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.

Public variable example


1 class PublicExample:
2 def __init__(self):
3 self.public_data = "This is public data"
4
5 def display(self):
6 print(self.public_data)
7
8 example = PublicExample()
9 [Link]() # Output: This is public data
10 example.public_data = "Modified public data"
11 [Link]() # Output: Modified public data

Protected Variable Example


1 class ProtectedExample:
2 def __init__(self):
3 self._protected_data = "This is protected data"
4

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

Private variable Example


1 class PrivateExample:
2 def __init__(self):
3 self.__private_data = "This is private data"
4
5 def __private_method(self):
6 print("Accessing private method")
7

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

Example: Getters and Setters

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

Example: Encapsulation with Properties


1 class Rectangle:
2 def __init__(self, width, height):
3 self.__width = width
4 self.__height = height
5
6 @property
7 def area(self):
8 return self.__width * self.__height
9
10 @property
11 def width(self):
12 return self.__width
13

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.

Q2: Create a BankAccount class with methods for deposit, withdrawal,


and balance checking.

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.

Q5: Implement a Rectangle and Square class where Square inher-


its from Rectangle, ensuring Square always has equal sides.

Q6: Write classes for different shapes (Circle, Square, Triangle)


each with an area method to demonstrate polymorphism.

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.

Q9: Implement a University class that contains a list of Department


objects, where each Department has Course objects.

Q10: Design a Library class that manages a collection of Book objects.


Include methods to add books, check out books, and return books.

Q11: Create a Vector class that supports vector addition and scalar mul-
tiplication using magic methods.

Q12: Implement a class hierarchy where FlyingCar inherits from both


Car and Airplane classes.

Q13: Design a MathOperations class with static methods for basic


math operations and a class method to return a constant.

Q14: Create a mixin for logging capabilities that can be added to any class
for logging actions.

Q15: Implement the singleton pattern to ensure only one instance of a


DatabaseConnection class can be created.

27
28
Chapter 3

File Processing

3.1 Basics of File Handling in Python


File handling is a fundamental concept in Python that enables interaction
with files, whether reading data, writing data, or performing other oper-
ations. Python treats files differently based on their type: text files and
binary files. Understanding this distinction is crucial for effective file ma-
nipulation.

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:

2. Log Management: Writing application logs to track events.

3. Data Storage: Saving user preferences or configurations.

4. File Parsing: Reading data from CSV, JSON, or XML files.

5. Report Generation: Writing output files for analysis or record-


keeping.

The basic syntax for creating file in Python is shown in listing 3.1

29
1 file = open("[Link]", "mode")
2

3 # Read the entire file


4 content = [Link]()
5
6 # Read a specific number of characters
7 content = [Link](10)
8
9 # Read a line at a time
10 line = [Link]()
11
12 # Read all lines into a list
13 lines = [Link]()
14 #close the file
15 [Link]()

Listing 3.1: File syntax demonstration


A more elegant and safer way to work with files is using the with state-
ment. Using the with statement automatically closes the file when the
block ends, even if an exception occurs. as compared with the listing 3.1.
Let us read a file using with statement as demonstrated in listing 3.2
1 with open("[Link]", "r") as file:
2 content = [Link]()

Listing 3.2: Automatically close the using with statement


User can also handle data that is not in English form by adding the encod-
ing format. Let see the example demonstration as shown in listing 3.3
1 with open("[Link]", "w", encoding="utf-8") as f:
2 [Link]("Non English language") # Writing in UTF-8
3

Listing 3.3: Advance data handling with encoding


Python provides extensive support for handling different types of files through
its built-in libraries and modules. Below, we’ll discuss various file types
and how Python handles them, along with code examples.

3.1.1 Text Files


Text files store data in a human-readable format using character encoding
like ASCII or UTF-8. Each line in a text file is typically terminated by a
newline character (\n). Commonly used text file types are:

30
• .txt files for plain text storage.
• .csv files for tabular data.
• .log files for logging activities.
• .json files for object serialization

1 # Writing to a text file


2 with open("[Link]", "w") as file:
3 [Link]("Hello, World!\n")
4 [Link]("Python file handling is powerful.")
5
6 # Reading from a text file
7 with open("[Link]", "r") as file:
8 content = [Link]()
9 print("Content of file:")
10 print(content)
11
12 # Appending to a text file
13 with open("[Link]", "a") as file:
14 [Link]("\nAppending new content!")

3.1.2 Binary Files


Binary files store data in a format that is not human-readable. The data is
stored as a series of bytes, and interpretation depends on the application’s
context. Common type fo binary used files are:
• .jpg, .png, .gif for images.
• .mp4, .mp3 for video and audio files.
• .exe, .dll for executable files.

1 # Writing to a binary file


2 data = b"This is binary data."
3 with open("[Link]", "wb") as file:
4 [Link](data)
5
6 # Reading from a binary file
7 with open("[Link]", "rb") as file:
8 content = [Link]()
9 print(content)

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

3 # Writing to a CSV file


4 data = [["Name", "Age"], ["Sade", 30], ["Tunde", 25]]
5 with open(’[Link]’, ’w’, newline=’’) as file:
6 writer = [Link](file)
7 [Link](data)
8

9 # Reading from a CSV file


10 with open(’[Link]’, ’r’) as file:
11 reader = [Link](file)
12 for row in reader:
13 print(row)
14

CSV files are extensively used in data analysis and machine learning, trans-
ferring tabular data between systems, and integrating with spreadsheet soft-
ware.

3.1.4 JSON Files


JSON (JavaScript Object Notation) files store data in a human-readable
format and are widely used in web development and API communication.
Pythonâs json module makes it easy to handle JSON files.
1 import json
2
3 # Writing to a JSON file
4 data = {"Name": "Sade", "Age": 30, "City": "Akure"}
5 with open(’[Link]’, ’w’) as file:
6 [Link](data, file)
7
8 # Reading from a JSON file
9 with open(’[Link]’, ’r’) as file:
10 content = [Link](file)
11 print(content)

JSON files are pivotal in applications like storing configuration settings,


sending and receiving data from web APIs, and serializing Python objects.
Majority of the developers send data inform of JSON rather than XML.

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])

XML files are common in configurations, data exchange between applica-


tions, and interfacing with web services. For instance [Link]
in Android application development.

3.1.6 Pickle Files


Pickle files allow storing Python objects in a binary format for later use.
The pickle module provides methods to serialize and deserialize objects.
1 import pickle
2
3 # Writing to a pickle file
4 data = {"Name": "Alice", "Age": 30}
5 with open(’[Link]’, ’wb’) as file:
6 [Link](data, file)
7

8 # Reading from a pickle file


9 with open(’[Link]’, ’rb’) as file:
10 content = [Link](file)
11 print(content)
12

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.

3. Multimedia Applications: Binary files handle media content like


images and audio.

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.

3.2 Understanding File Modes


Python supports various modes for file operations, each tailored to specific
use cases, the table 3.1 discuss various file mode operation used in Python.

Table 3.1: Overview of File Modes in Python

Mode Description Example Code Application


’r’ Opens a file for read- file = Reading content from
ing (default mode). File open(’[Link]’, file.
must exist, or an error ’r’)
occurs.
’w’ Opens a file for writing. file = Writing or overwriti
Creates a new file if it open(’[Link]’, content in a file.
doesnât exist or trun- ’w’)
cates the file if it exists.
’x’ Opens a file for exclu- file = Safely creating n
sive creation. If the file open(’[Link]’, files.
exists, operation fails. ’x’)

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.

3.3 Reading Files in Python

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:

1. read() The read() method reads the entire content of a file as a


single string. It is useful when dealing with small files. Here is an example:
1 with open(’[Link]’, ’r’) as file:
2 content = [Link]()
3 print(content)

2. readline() The readline() method reads one line at a time


from the file. It is beneficial when you only need specific lines. Example:
1 with open(’[Link]’, ’r’) as file:
2 line = [Link]()
3 print(line)

3. readlines() The readlines() method reads all lines of a file


and returns them as a list of strings. Example:
1 with open(’[Link]’, ’r’) as file:
2 lines = [Link]()
3 for line in lines:
4 print(line)

3.3.2 Iterating Through File Content Line by Line


For efficient processing of file content, you can iterate through the file ob-
ject directly. This approach uses less memory compared to readlines()
since it reads one line at a time:
1 with open(’[Link]’, ’r’) as file:
2 for line in file:
3 print([Link]()) # Use strip() to remove extra
whitespace

This method is particularly useful when working with large files, as it


avoids loading the entire file into memory.

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)

2. Use Buffered Reading Buffered reading allows you to control the


amount of data read at a time. For example:
1 with open(’large_file.txt’, ’r’) as file:
2 while chunk := [Link](1024): # Read in chunks of
1024 bytes
3 process_chunk(chunk)

3. Utilize External Libraries For extremely large files, consider using


specialized libraries like pandas for CSVs or TSV (tab separated value)
or pyarrow for binary formats to handle data more efficiently.

4. Memory Mapping Memory mapping is another efficient technique


for reading parts of large files. The mmap module can be used for this
purpose.
1 import mmap
2
3 with open(’large_file.txt’, ’r’) as file:
4 with [Link]([Link](), length=0, access=mmap.
ACCESS_READ) as mm:
5 print([Link]()) # Read lines from the memory-
mapped file

3.4 Writing and Appending to Files


Python provides straightforward methods for writing and appending
data to files, enabling efficient and flexible file management. This section

37
explores these methods in detail and highlights key considerations.

3.4.1 Writing Data with write() and writelines()


Writing data to files in Python can be done using the write() and writelines()
methods. These methods are commonly used in file operations:

1. write() The write() method writes a string to a file. It does


not add a newline character automatically, so the user must include it if
required. Example:
1 with open(’[Link]’, ’w’) as file:
2 [Link](’Hello, World!\n’)
3 [Link](’This is a new line.’)

This will create a file named [Link] with the specified content.

2. writelines() The writelines() method writes a list of strings


to the file. Unlike write(), it does not add newline characters between
strings, so you must include them in the input. Example:
1 data = ["Line 1\n", "Line 2\n", "Line 3\n"]
2 with open(’[Link]’, ’w’) as file:
3 [Link](data)

writelines() is useful when you already have data stored in a list


format.

3.4.2 Appending Data Using a Mode


The a mode (append mode) allows you to add data to the end of an existing
file without overwriting its current content. This is particularly useful for
logging or cumulative data storage. Example:
1 with open(’[Link]’, ’a’) as file:
2 [Link](’Appended line\n’)

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.

3.4.3 Overwriting vs Appending: Key Differences


When working with files, understanding the difference between overwrit-
ing and appending is essential:

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’)

2. Appending (a Mode) The a mode retains the existing content of the


file and adds new data to the end. This mode is suitable for preserving
historical data while adding updates.
1 # Open the file in append mode
2 with open(’[Link]’, ’a’) as file:
3 [Link](’This is a new line appended to the file.\n’
)
4 [Link](’Appending another line.\n’)
5
6 print("Data has been appended to the file.")
7

3.5 File Handling with Context Managers


Context managers in Python simplify file handling by managing resources
efficiently. This section explores how to use context managers for file op-
erations and the advantages they offer.

3.5.1 Using the with open() Statement


The with open() statement is a common pattern in Python for file han-
dling. It ensures that a file is properly closed after its operations are com-
plete, even if an error occurs during the process. Here is a basic example:
1 with open(’[Link]’, ’r’) as file:
2 content = [Link]()
3 print(content)

In this example: - ’[Link]’ is opened in read mode (’r’). -


The file object file is automatically closed at the end of the with block.
The with statement eliminates the need to explicitly call [Link]().
Majority of the developer do forget to close the file after use. This can lead
the file to attack from another user.

39
3.5.2 Benefits of Automatic File Closure
Using context managers for file handling provides several benefits:

1. Reduces Boilerplate Code You do not need to write explicit close()


calls, making the code more concise and readable.

2. Ensures Proper Resource Management Files are closed automati-


cally, preventing resource leaks or accidental file locks. This is particularly
important in large applications or when dealing with multiple files.

3. Handles Exceptions Gracefully If an exception occurs within the


with block, the file is still closed properly, ensuring stability.
Example with exception handling:
1 try:
2 with open(’[Link]’, ’r’) as file:
3 for line in file:
4 print([Link]())
5 except FileNotFoundError:
6 print("The file does not exist.")

In this example, even if the file is missing or an error occurs while


reading, the file closure is managed automatically.

3.5.3 Writing Cleaner and Safer File Handling Code


Context managers encourage writing cleaner and safer code. Here are some
tips:

1. Combining File Operations You can perform multiple operations


within the with block:
1 with open(’[Link]’, ’r’) as infile, open(’[Link]
’, ’w’) as outfile:
2 for line in infile:
3 [Link]([Link]()) # Write uppercase lines
to output

This example demonstrates simultaneous reading from one file and


writing to another.

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)

3. Leveraging Context Managers in Libraries Many Python libraries


use context managers for file-like operations. For example, the gzip mod-
ule for compressed files:
1 import gzip
2
3 with [Link](’[Link]’, ’rt’) as file:
4 for line in file:
5 print([Link]())

3.6 Error Handling and Best Practices


Effective file handling in Python involves managing errors and adopting
best practices to ensure smooth and efficient operations. This section dis-
cusses common errors, efficient error-handling techniques, and practical
tips for safe file management.

3.6.1 Common File Handling Errors and Their Causes


File handling operations can encounter various errors. Understanding these
errors helps in designing robust applications. Some common errors in-
clude:

1. FileNotFoundError This occurs when attempting to access a file that


does not exist. This will easily break your code. For instance:
1 with open(’non_existent_file.txt’, ’r’) as file:
2 content = [Link]() # Raises FileNotFoundError

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

3. IsADirectoryError This occurs when a directory is accessed as if it


were a file. Example:
1 with open(’/path_to_directory’, ’r’) as file:
2 content = [Link]() # Raises IsADirectoryError

4. ValueError This occurs when an invalid mode or operation is used in


file handling. Example:
1 file = open(’[Link]’, ’invalid_mode’) # Raises
ValueError

3.6.2 Using try-except for Robust Error Handling


The try-except construct allows graceful handling of errors, ensuring
that the program does not crash unexpectedly. It also give more informa-
tion to the user to know which type of error in case an error occur in the
program unexpectedly. Example:
1 try:
2 with open(’[Link]’, ’r’) as file:
3 content = [Link]()
4 print(content)
5 except FileNotFoundError:
6 print("Error: The file does not exist.")
7 except PermissionError:
8 print("Error: Permission denied.")
9 except Exception as e:
10 print(f"An unexpected error occurred: {e}")

This approach ensures that specific errors are addressed while other
exceptions are also captured for debugging.

3.6.3 Tips for Safe and Efficient File Operations


Here are some best practices to follow when working with files:

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")

3. Handle Large Files Efficiently Use line-by-line reading or chunk-


based processing for large files:
1 with open(’large_file.txt’, ’r’) as file:
2 for line in file:
3 process_line(line)

4. Backup Important Files Before performing write operations, create


backups of important files to prevent data loss.

3.6.4 Ensuring Cross-Platform Compatibility


File handling operations may behave differently across operating systems.
To ensure cross-platform compatibility:

1. Use [Link] for Path Manipulations The [Link] module pro-


vides functions for handling file paths in a platform-independent way:
1 import os
2

3 file_path = [Link](’folder’, ’[Link]’)


4 print(file_path) # Outputs ’folder/[Link]’ on Linux
and ’folder\\[Link]’ on Windows

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. Be Aware of Encoding Differences Specify the encoding explicitly


when working with text files to avoid issues:
1 with open(’[Link]’, ’r’, encoding=’utf-8’) 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.

Q2: Develop a program that writes a user-defined list of strings to a file


using the writelines() method. Ensure that each string in the
list is written on a new line.

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.

Q10: Develop a Python program to encrypt a text file’s content using a


simple cipher (e.g., Caesar cipher) and write the encrypted content
to a new file. Provide a decryption option as well.

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.

Q14: Develop a program to monitor changes in a file. The program should


run continuously and print any new content added to the file in real-
time.

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

[1] Python Documentation. Available at [Link]


org/3/.

49
50
Glossary

Interpreter: A program that directly executes instructions written in a pro-


gramming language.
Syntax: The set of rules that defines the combinations of symbols consid-
ered as valid programs.

51
52

You might also like