0% found this document useful (0 votes)
15 views

Python Lab Program

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views

Python Lab Program

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 42

Ex:1

Python Lab Program: Function Types and Scopes Analysis

Aim:
To analyze the scopes of different types of functions in Python, including global, local, and
nonlocal scopes, using print statements and debugging tools like pdb.

Algorithm:
1. Step 1: Understand Function Scopes:

o Global Scope: Variables defined outside any function or class. Accessible


from anywhere in the code.

o Local Scope: Variables defined within a function. Accessible only within that
function.

o Nonlocal Scope: Variables used in nested functions. They are neither local nor
global but belong to the nearest enclosing function.

2. Step 2: Setup the Environment:

o Write a Python script that demonstrates the use of global, local, and nonlocal
variables.

o Use print statements to trace the values of variables in different scopes.

3. Step 3: Define a Global Variable:

o Define a global variable outside all functions.

o Write a function that accesses and modifies this global variable using the
global keyword.

4. Step 4: Create a Function with Local Scope:

o Inside the function, define a local variable.


o Use print statements to show that this variable is not accessible outside the
function.

5. Step 5: Create a Nested Function for Nonlocal Scope:

o Define a function inside another function.

o Inside the inner function, use the nonlocal keyword to modify a variable from
the enclosing function’s scope.

o Use print statements to demonstrate how the variable's value changes.

6. Step 6: Debugging with pdb:


o Use Python's built-in debugger pdb to step through the code and inspect the
scope of variables.

o Set breakpoints at key points in the code to analyze the flow and scope.
7. Step 7: Run and Analyze the Program:

o Run the program and analyze the output from the print statements and the pdb
debugger.

8. Step 8: Document the Results:

o Document the behavior of global, local, and nonlocal variables as observed in


the program.

# Global variable

global_var = "I am global!"

def outer_function():

# Local variable in the outer function

outer_var = "I am local to outer_function!"

def inner_function():

# Accessing nonlocal variable

nonlocal outer_var

outer_var = "I am modified by inner_function!"

print("Inside inner_function:", outer_var)

print("Before calling inner_function:", outer_var)

inner_function()

print("After calling inner_function:", outer_var)


def modify_global():
global global_var

global_var = "I am modified globally!"

print("Before modify_global call:", global_var)

modify_global()

print("After modify_global call:", global_var)

outer_function()
# Using pdb for debugging (optional)

import pdb; pdb.set_trace()

# Global variable access outside any function

print("Outside all functions:", global_var)

output:

Before modify_global call: I am global!

After modify_global call: I am modified globally!


Before calling inner_function: I am local to outer_function!

Inside inner_function: I am modified by inner_function!

After calling inner_function: I am modified by inner_function!

Ex:2

Python Lab Program: Argument Passing Techniques Comparison

Aim:
To compare different argument passing techniques in Python functions, including positional
arguments, keyword arguments, default arguments, and variable-length arguments, through
experimental evaluation.

Algorithm:
1. Step 1: Understand Argument Passing Techniques:

o Positional Arguments: Arguments passed to a function based on their


position.
o Keyword Arguments: Arguments passed to a function by explicitly naming
each one.

o Default Arguments: Arguments that assume a default value if not provided by


the caller.

o Variable-length Arguments: Allows a function to accept any number of


arguments using *args for non-keyword and **kwargs for keyword arguments.

2. Step 2: Setup the Environment:

o Write a Python script that includes multiple functions demonstrating each type
of argument passing.
o Use print statements to display the behavior of each function.

3. Step 3: Define Functions for Each Technique:

o Create a function that uses positional arguments.

o Create a function that uses keyword arguments.

o Create a function that uses default arguments.

o Create a function that uses variable-length arguments.

4. Step 4: Compare Argument Passing Techniques:

o Call each function with different sets of arguments.


o Compare how the functions handle the arguments and how the outputs differ
based on the type of argument passing.

5. Step 5: Document the Results:


o Document the behavior of each function and the differences between argument
passing techniques.
6. Step 6: Run and Analyze the Program:

o Run the program and analyze the output for each argument passing technique.

# Positional Arguments

def positional_example(a, b):

print("Positional Example - a:", a, "b:", b)

# Keyword Arguments

def keyword_example(a, b):

print("Keyword Example - a:", a, "b:", b)

# Default Arguments

def default_example(a, b=10):

print("Default Example - a:", a, "b:", b)

# Variable-Length Arguments (*args for non-keyword, **kwargs for keyword)


def variable_length_example(*args, **kwargs):

print("Variable-Length Example - args:", args, "kwargs:", kwargs)


# Experimenting with Positional Arguments
print("Calling positional_example(1, 2):")

positional_example(1, 2)

# Experimenting with Keyword Arguments

print("\nCalling keyword_example(a=1, b=2):")

keyword_example(a=1, b=2)

print("Calling keyword_example(b=2, a=1):")

keyword_example(b=2, a=1)

# Experimenting with Default Arguments


print("\nCalling default_example(5):")

default_example(5)

print("Calling default_example(5, 15):")

default_example(5, 15)

# Experimenting with Variable-Length Arguments

print("\nCalling variable_length_example(1, 2, 3, x=10, y=20):")

variable_length_example(1, 2, 3, x=10, y=20)

print("Calling variable_length_example(x=10, y=20):")

variable_length_example(x=10, y=20)

output:

Calling positional_example(1, 2):


Positional Example - a: 1 b: 2

Calling keyword_example(a=1, b=2):


Keyword Example - a: 1 b: 2

Calling keyword_example(b=2, a=1):

Keyword Example - a: 1 b: 2

Calling default_example(5):

Default Example - a: 5 b: 10
Calling default_example(5, 15):
Default Example - a: 5 b: 15

Calling variable_length_example(1, 2, 3, x=10, y=20):

Variable-Length Example - args: (1, 2, 3) kwargs: {'x': 10, 'y': 20}

Calling variable_length_example(x=10, y=20):

Variable-Length Example - args: () kwargs: {'x': 10, 'y': 20}

=== Code Execution Successful ===

Ex:3

Python Lab Program: Demonstrating Unpacking of Function Arguments Using *args


and **kwargs

Aim:
To create experiments that demonstrate the unpacking of function arguments in Python using
*args (non-keyword arguments) and **kwargs (keyword arguments).

Algorithm:
1. Step 1: Understand Argument Unpacking:

o *args: Allows a function to accept a variable number of positional arguments,


which are packed into a tuple.

o **kwargs: Allows a function to accept a variable number of keyword


arguments, which are packed into a dictionary.

2. Step 2: Setup the Environment:

o Write a Python script that includes multiple functions demonstrating


unpacking using *args and **kwargs.

o Use print statements to display how the arguments are unpacked inside the
function.

3. Step 3: Create Functions to Demonstrate *args:

o Define a function that takes *args as a parameter.

o Inside the function, unpack the arguments and demonstrate different ways to
use them.

4. Step 4: Create Functions to Demonstrate **kwargs:


o Define a function that takes **kwargs as a parameter.
o Inside the function, unpack the keyword arguments and demonstrate how they
can be accessed and used.

5. Step 5: Combine *args and **kwargs:


o Create a function that accepts both *args and **kwargs.

o Demonstrate how the function handles a mixture of positional and keyword


arguments.

6. Step 6: Run and Analyze the Program:

o Run the program and analyze how *args and **kwargs are unpacked and
utilized in each experiment.

# Function to demonstrate *args

def demo_args(*args):

print("Received *args as a tuple:", args)

for i, arg in enumerate(args):

print(f"Argument {i}: {arg}")

# Function to demonstrate **kwargs

def demo_kwargs(**kwargs):

print("Received **kwargs as a dictionary:", kwargs)

for key, value in kwargs.items():

print(f"{key}: {value}")

# Function to demonstrate combined use of *args and **kwargs


def demo_args_kwargs(*args, **kwargs):

print("Received *args:", args)

print("Received **kwargs:", kwargs)

# Experimenting with *args

print("Calling demo_args(1, 2, 3, 4):")


demo_args(1, 2, 3, 4)
# Experimenting with **kwargs

print("\nCalling demo_kwargs(a=10, b=20, c=30):")

demo_kwargs(a=10, b=20, c=30)

# Experimenting with combined *args and **kwargs

print("\nCalling demo_args_kwargs(1, 2, 3, x=10, y=20):")

demo_args_kwargs(1, 2, 3, x=10, y=20)

# Unpacking a list and a dictionary into *args and **kwargs

args_list = [1, 2, 3, 4]

kwargs_dict = {'a': 10, 'b': 20, 'c': 30}

print("\nCalling demo_args_kwargs with unpacked list and dictionary:")

demo_args_kwargs(*args_list, **kwargs_dict)

output:

alling demo_args(1, 2, 3, 4):

Received *args as a tuple: (1, 2, 3, 4)

Argument 0: 1

Argument 1: 2
Argument 2: 3

Argument 3: 4

Calling demo_kwargs(a=10, b=20, c=30):

Received **kwargs as a dictionary: {'a': 10, 'b': 20, 'c': 30}

a: 10

b: 20
c: 30
Calling demo_args_kwargs(1, 2, 3, x=10, y=20):

Received *args: (1, 2, 3)

Received **kwargs: {'x': 10, 'y': 20}

Calling demo_args_kwargs with unpacked list and dictionary:

Received *args: (1, 2, 3, 4)


Received **kwargs: {'a': 10, 'b': 20, 'c': 30}

=== Code Execution Successful ===

Ex:5

Python Lab Program: Exploring Assertion Testing in Python

Aim:
To explore the usage and effectiveness of assertions in debugging Python code by designing
experiments with custom assertions.

Algorithm:
1. Step 1: Understand Assertions:

o An assertion is a statement that checks whether a condition is true at a specific


point in the program.

o If the condition is False, an AssertionError is raised, halting the program.

o Assertions are typically used to catch bugs during development and are not
meant to handle runtime errors in production.

2. Step 2: Setup the Environment:

o Write a Python script with multiple functions, each containing custom


assertions to validate different conditions.

o These functions will include logical checks where the correctness of the
conditions can be asserted.
3. Step 3: Design Custom Assertions:
o Design assertions to check the validity of inputs, boundary conditions, and
logical flows within functions.

o Create assertions for various scenarios like checking list lengths, value ranges,
string contents, etc.

4. Step 4: Test the Assertions:

o Call the functions with both valid and invalid inputs to trigger the assertions.

o Observe how the assertions help in identifying logical errors early in the
program.

5. Step 5: Document the Results:

o Document the scenarios where assertions catch errors and how they contribute
to debugging.

import math

import time

import numpy as np

# Experiment 1: Basic Assertion to Validate Function Inputs

def safe_sqrt(x):

assert x >= 0, f"Expected non-negative number, got {x}"

return math.sqrt(x)

# Test Experiment 1

print("Experiment 1: Basic Assertion to Validate Function Inputs")

try:

print(safe_sqrt(9)) # Expected: 3.0

print(safe_sqrt(-4)) # Should raise an assertion error

except AssertionError as e:
print(f"AssertionError: {e}")
print()

# Experiment 2: Custom Assertion for Complex Data Validation

def process_students(students):

for student in students:

assert 'name' in student and 'age' in student and 'grade' in student, \

f"Missing keys in student data: {student}"


# Process student data

print(f"Processing {student['name']}")

# Test Experiment 2

print("Experiment 2: Custom Assertion for Complex Data Validation")

students_data = [

{'name': 'Alice', 'age': 20, 'grade': 'A'},

{'name': 'Bob', 'grade': 'B'}, # Missing 'age'

try:

process_students(students_data) # Should raise an assertion error for the second student

except AssertionError as e:
print(f"AssertionError: {e}")

print()

# Experiment 3: Assertions to Validate Post-Conditions

def sort_list(numbers):

sorted_numbers = sorted(numbers)
assert all(sorted_numbers[i] <= sorted_numbers[i+1] for i in range(len(sorted_numbers)-
1)), \

"List is not sorted"


return sorted_numbers

# Test Experiment 3

print("Experiment 3: Assertions to Validate Post-Conditions")

try:

print(sort_list([3, 1, 2])) # Expected: [1, 2, 3]


print(sort_list([3, 2, 1])) # Should pass as it's sorted internally

except AssertionError as e:

print(f"AssertionError: {e}")

print()

# Experiment 4: Custom Assertions for Unit Testing


def factorial(n):

assert n >= 0, "Factorial is not defined for negative numbers"

if n == 0 or n == 1:

return 1

return n * factorial(n-1)

def test_factorial():

assert factorial(0) == 1, "Failed on factorial(0)"

assert factorial(1) == 1, "Failed on factorial(1)"

assert factorial(5) == 120, "Failed on factorial(5)"


assert factorial(7) == 5040, "Failed on factorial(7)"
# Test for an edge case with invalid input

try:

factorial(-1) # Should raise an assertion error

except AssertionError as e:

print(f"AssertionError in test_factorial: {e}")

# Test Experiment 4

print("Experiment 4: Custom Assertions for Unit Testing")


test_factorial()

print()

# Experiment 5: Assertions in Performance-Critical Code

def matrix_multiply(A, B):

assert len(A[0]) == len(B), "Incompatible matrix dimensions"

result = np.dot(A, B)

return result

# Test Experiment 5

print("Experiment 5: Assertions in Performance-Critical Code")

# Create large matrices

A = np.random.rand(1000, 1000)
B = np.random.rand(1000, 1000)

# Measure performance with assertions

start_time = time.time()

try:
result_with_assertions = matrix_multiply(A, B)
print(f"Time with assertions: {time.time() - start_time:.4f} seconds")

except AssertionError as e:

print(f"AssertionError: {e}")

# Measure performance without assertions

start_time = time.time()

result_without_assertions = np.dot(A, B) # Directly multiply without assertions

print(f"Time without assertions: {time.time() - start_time:.4f} seconds")

output:

xperiment 1: Basic Assertion to Validate Function Inputs

3.0

AssertionError: Expected non-negative number, got -4

Experiment 2: Custom Assertion for Complex Data Validation

Processing Alice

AssertionError: Missing keys in student data: {'name': 'Bob', 'grade': 'B'}

Experiment 3: Assertions to Validate Post-Conditions

[1, 2, 3]
[1, 2, 3]

Experiment 4: Custom Assertions for Unit Testing

AssertionError in test_factorial: Factorial is not defined for negative numbers

Experiment 5: Assertions in Performance-Critical Code

Time with assertions: 0.0140 seconds


Time without assertions: 0.0188 second
Ex:6

Python Lab Program: Recursion Performance Analysis

Aim:
To measure and compare the performance of recursive functions with their iterative
counterparts for various problem sets, such as calculating the factorial, Fibonacci sequence,
and sum of an array.

Algorithm:
1. Step 1: Understand Recursion and Iteration:

o Recursion: A function calls itself to solve a smaller instance of the problem


until a base case is reached.

o Iteration: A loop is used to solve the problem by repeatedly executing a set of


instructions.
2. Step 2: Select Problem Sets:

o Choose problems that can be solved using both recursive and iterative
methods, such as:

 Calculating the factorial of a number.

 Generating the Fibonacci sequence.

 Summing the elements of an array.

3. Step 3: Implement Recursive Functions:

o Write Python functions that solve each problem using recursion.


4. Step 4: Implement Iterative Functions:

o Write Python functions that solve the same problems using iteration.

5. Step 5: Measure Performance:

o Use Python’s time module to measure the execution time of both recursive and
iterative functions.

o Run each function multiple times to obtain average execution times.

6. Step 6: Compare Results:

o Compare the execution times of recursive and iterative solutions.

o Analyze the scenarios where recursion is less or more efficient than iteration.

7. Step 7: Document Findings:


o Summarize the results, highlighting the performance differences and
discussing the trade-offs between recursion and iteration.

import time

# Recursive function to calculate factorial

def factorial_recursive(n):

if n == 0 or n == 1:

return 1

else:

return n * factorial_recursive(n - 1)

# Iterative function to calculate factorial

def factorial_iterative(n):

result = 1

for i in range(2, n + 1):

result *= i

return result

# Recursive function to calculate nth Fibonacci number

def fibonacci_recursive(n):

if n <= 1:

return n

else:

return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)

# Iterative function to calculate nth Fibonacci number

def fibonacci_iterative(n):

a, b = 0, 1
for _ in range(n):
a, b = b, a + b

return a

# Recursive function to sum elements of an array

def sum_array_recursive(arr):

if len(arr) == 0:

return 0

else:
return arr[0] + sum_array_recursive(arr[1:])

# Iterative function to sum elements of an array

def sum_array_iterative(arr):

total = 0

for num in arr:

total += num

return total

# Function to measure performance

def measure_time(func, *args):

start = time.time()

result = func(*args)
end = time.time()

return result, end - start

# Test data

n = 30

arr = list(range(1, 1001))

# Measure and compare factorial


print("Factorial of", n)

result, time_recursive = measure_time(factorial_recursive, n)

print("Recursive:", result, "Time:", time_recursive)

result, time_iterative = measure_time(factorial_iterative, n)

print("Iterative:", result, "Time:", time_iterative)

# Measure and compare Fibonacci

print("\nFibonacci number at position", n)


result, time_recursive = measure_time(fibonacci_recursive, n)

print("Recursive:", result, "Time:", time_recursive)

result, time_iterative = measure_time(fibonacci_iterative, n)

print("Iterative:", result, "Time:", time_iterative)

# Measure and compare sum of array

print("\nSum of array")

result, time_recursive = measure_time(sum_array_recursive, arr)

print("Recursive:", result, "Time:", time_recursive)

result, time_iterative = measure_time(sum_array_iterative, arr)

print("Iterative:", result, "Time:", time_iterative)

Ex:7 Inheritance

Aim:
The aim of an inheritance program in Python is to illustrate the concept of inheritance, where
a derived class inherits attributes and methods from a base class, allowing for code reuse and
extension. This concept enables creating a hierarchy of classes where derived classes can
override or extend the behavior of base classes.

Algorithm for an Inheritance Program:

1. Define the Base Class:


o Create a base class that contains common attributes and methods that will be
inherited by derived classes.

o Implement an __init__ method to initialize the base class attributes.


o Define methods that can be overridden or used as-is by derived classes.

2. Define Derived Classes:


o Create derived classes that inherit from the base class.

o Use the super() function in the __init__ method of the derived classes to
initialize attributes from the base class.

o Override base class methods to provide specific implementations relevant to


the derived class.

o Add additional attributes or methods specific to the derived classes if needed.

3. Create Instances:
o Instantiate objects of the base class and derived classes to demonstrate how
inheritance works.

4. Demonstrate Inheritance:
o Call methods on instances of the base and derived classes to show inherited
and overridden behavior.

o Use functions like isinstance() to check the type of instances and confirm
inheritance.

class Animal:

def __init__(self, name):

self.name = name

def speak(self):

return "Some generic animal sound"

def describe(self):

return f"This is a {self.name}."

class Dog(Animal):
def __init__(self, name, breed):

super().__init__(name) # Call the __init__ method of the base class

self.breed = breed

def speak(self):

return "Woof!"

def describe(self):
return f"This is a {self.breed} dog named {self.name}."

class Cat(Animal):

def __init__(self, name, color):

super().__init__(name) # Call the __init__ method of the base class

self.color = color

def speak(self):

return "Meow!"

def describe(self):

return f"This is a {self.color} cat named {self.name}."

# Create instances of each class

animal = Animal("generic animal")


dog = Dog("Buddy", "Golden Retriever")

cat = Cat("Whiskers", "black")

# Demonstrate behavior of inherited methods and attributes

print(animal.describe()) # This is a generic animal.


print(animal.speak()) # Some generic animal sound
print(dog.describe()) # This is a Golden Retriever dog named Buddy.

print(dog.speak()) # Woof!

print(cat.describe()) # This is a black cat named Whiskers.

print(cat.speak()) # Meow!

# Show that Dog and Cat instances can access methods from Animal
print(isinstance(dog, Animal)) # True

print(isinstance(cat, Animal)) # True

# Show that methods in derived classes override base class methods

print(dog.speak()) # Woof!

print(cat.speak()) # Meow!

Outout:

This is a generic animal.

Some generic animal sound

This is a Golden Retriever dog named Buddy.

Woof!
This is a black cat named Whiskers.

Meow!
True

True

Woof!

Meow!
Ex:8 File handling

Aim:
The aim of file handling in Python is to enable programs to perform operations on files, such
as creating, reading, writing, and deleting files. This allows programs to manage persistent
data storage and retrieve information as needed. File handling is crucial for applications that
need to store data permanently or share data between different runs of the program.

Algorithm for File Handling:

1. Open a File:
o Use the open() function to access a file.

o Specify the file name and mode ('r', 'w', 'a', 'b', etc.).

2. Perform Operations on the File:

o Reading:
 Use read(), readline(), or readlines() methods to read the content.

o Writing:
 Use write() or writelines() methods to write content to the file.

o Appending:
 Use 'a' mode and write() or writelines() to add content to the end of the
file.

o Binary Handling:
 Use 'b' mode to handle binary files and use read() or write() for binary
data.

3. Close the File:


o Use file.close() to close the file and save changes.

o Alternatively, use the with statement to automatically close the file.

4. Handle Exceptions:
o Implement error handling to manage scenarios such as file not found or
permission issues using try and except blocks.

5. File Path Operations:


o Use modules like os and pathlib to manage file paths, check existence, and
delete files.

import os

from pathlib import Path

def create_and_write_file(file_name, content):

"""Create a file and write content to it."""


with open(file_name, 'w') as file:

file.write(content)
print(f"File '{file_name}' created and written to.")

def read_file(file_name):

"""Read content from a file."""

with open(file_name, 'r') as file:

content = file.read()
print(f"Content of '{file_name}':\n{content}")

def append_to_file(file_name, content):

"""Append content to an existing file."""

with open(file_name, 'a') as file:

file.write(content)

print(f"Content appended to '{file_name}'.")

def delete_file(file_name):

"""Delete a file."""
try:
os.remove(file_name)

print(f"File '{file_name}' deleted.")

except FileNotFoundError:

print(f"File '{file_name}' not found.")

def write_binary_file(file_name, binary_data):

"""Write binary data to a file."""

with open(file_name, 'wb') as file:


file.write(binary_data)

print(f"Binary data written to '{file_name}'.")

def read_binary_file(file_name):

"""Read binary data from a file."""

with open(file_name, 'rb') as file:

binary_data = file.read()

print(f"Binary data read from '{file_name}':\n{binary_data}")

def file_operations_demo():

text_file = 'sample.txt'

binary_file = 'sample.bin'

# Creating and writing to a text file

create_and_write_file(text_file, 'Hello, Python file handling!\nThis is a new line.')

# Reading the text file

read_file(text_file)

# Appending to the text file


append_to_file(text_file, '\nAppended line.')
# Reading the text file again to see the appended content

read_file(text_file)

# Creating and writing binary data to a file

binary_data = bytes([120, 3, 255, 0, 100]) # Example binary data

write_binary_file(binary_file, binary_data)

# Reading binary data from the file

read_binary_file(binary_file)

# Deleting the files

delete_file(text_file)

delete_file(binary_file)

if __name__ == "__main__":

file_operations_demo()

ouput:

File 'sample.txt' created and written to.

Content of 'sample.txt':
Hello, Python file handling!

This is a new line.


Content appended to 'sample.txt'.

Content of 'sample.txt':

Hello, Python file handling!

This is a new line.

Appended line.
Binary data written to 'sample.bin'.
Binary data read from 'sample.bin':

b'x\x03\xff\x00d'

File 'sample.txt' deleted.

File 'sample.bin' deleted.

PS C:\Users\sures>

Ex:9 Structured text files

Aim:
The aim of experimenting with parsing different structured text files (CSV, XML, HTML,
and JSON) is to understand the structure and performance implications of each format. This
involves learning how to read, write, and manipulate data in these formats, as well as
comparing their performance in terms of parsing time and memory usage.

Algorithm for Structured Text File Parsing:

1. Parsing CSV Files

1. Create a CSV File:


o Use Python’s csv module to write tabular data to a file.

2. Read and Parse CSV File:


o Open the file using csv.reader to read the content.

o Process each row of the CSV file.

3. Measure Performance:
o Use the time module to measure the time taken to parse large CSV files.

2. Parsing XML Files

1. Create an XML File:


o Use any text editor to create an XML file with nested elements and attributes.

2. Read and Parse XML File:


o Use Python’s xml.etree.ElementTree module to parse the XML file.

o Traverse the XML tree and extract data.

3. Measure Performance:
o Measure the time taken to parse large XML files.

3. Parsing HTML Files


1. Create an HTML File:
o Create an HTML file with various tags and content.

2. Read and Parse HTML File:


o Use Python’s BeautifulSoup library to parse the HTML content.

o Extract data by navigating the HTML tags.

3. Measure Performance:
o Measure the time taken to parse and extract data from large HTML files.

4. Parsing JSON Files


1. Create a JSON File:
o Create a JSON file with nested objects and arrays.

2. Read and Parse JSON File:


o Use Python’s json module to load and parse the JSON data.

o Access the data using Python dictionaries and lists.

3. Measure Performance:
o Measure the time taken to parse large JSON files.

import csv

import timeit

# Sample CSV data

csv_data = """name,age,city

John,23,New York
Jane,29,Los Angeles

Doe,31,Chicago"""

# Write the CSV data to a file

with open("test.csv", "w") as file:

file.write(csv_data)

# Function to parse CSV


def parse_csv():

with open("test.csv", newline='') as csvfile:

reader = csv.DictReader(csvfile)

return [row for row in reader]

# Measure the time to parse CSV

csv_time = timeit.timeit(parse_csv, number=1000)

print(f"CSV Parsing Time: {csv_time:.6f} seconds")


import xml.etree.ElementTree as ET

import timeit

# Sample XML data

xml_data = """<root>

<person>

<name>John</name>

<age>23</age>

<city>New York</city>

</person>

<person>

<name>Jane</name>

<age>29</age>
<city>Los Angeles</city>

</person>
</root>"""

# Write the XML data to a file

with open("test.xml", "w") as file:

file.write(xml_data)
# Function to parse XML

def parse_xml():

tree = ET.parse("test.xml")

root = tree.getroot()

return [{child.tag: child.text for child in person} for person in root]

# Measure the time to parse XML

xml_time = timeit.timeit(parse_xml, number=1000)


print(f"XML Parsing Time: {xml_time:.6f} seconds")

import timeit

from bs4 import BeautifulSoup

# Sample HTML data

html_data = """<html>

<body>

<table>

<tr><td>John</td><td>23</td><td>New York</td></tr>

<tr><td>Jane</td><td>29</td><td>Los Angeles</td></tr>

</table>

</body>

</html>"""

# Write the HTML data to a file


with open("test.html", "w") as file:

file.write(html_data)

# Function to parse HTML

def parse_html():
with open("test.html", "r") as file:
soup = BeautifulSoup(file, 'html.parser')

table = soup.find('table')

return [[cell.text for cell in row.find_all('td')] for row in table.find_all('tr')]

# Measure the time to parse HTML

html_time = timeit.timeit(parse_html, number=1000)

print(f"HTML Parsing Time: {html_time:.6f} seconds")


import json

import timeit

# Sample JSON data

json_data = """

{"name": "John", "age": 23, "city": "New York"},

{"name": "Jane", "age": 29, "city": "Los Angeles"}

"""

# Write the JSON data to a file

with open("test.json", "w") as file:


file.write(json_data)

# Function to parse JSON

def parse_json():

with open("test.json", "r") as file:

return json.load(file)

# Measure the time to parse JSON


json_time = timeit.timeit(parse_json, number=1000)

print(f"JSON Parsing Time: {json_time:.6f} seconds")

EX: 10 a) Simple Web application using Django


Aim:

The aim of this lab is to guide students through the process of setting up a Django
development environment. By the end of this lab, students should be able to:

Steps:

 Install Python and verify the installation.


 Set up and activate a Python virtual environment.
 Install Django within the virtual environment.
 Create a new Django project and understand the basic structure.
 Run the Django development server and verify that the setup is successful.

Step 1: Set Up Your Django Environment


1. Install Django: Make sure you have Django installed. You can install it using pip if
you haven't already:

bash

Copy code

pip install django

2. Create a Django Project: Create a new Django project by running:

django-admin startproject helloworld_project


Navigate into your project directory:

bash

Copy code

cd helloworld_project

3. Create a Django App: Create a new app within your project:

bash

Copy code
python manage.py startapp helloworld_app
Step 2: Set Up Your Django App
1. Add the App to Your Project: Open helloworld_project/settings.py and add
helloworld_app to the INSTALLED_APPS list:
python

Copy code

INSTALLED_APPS = [

...

'helloworld_app',

2. Create a View: In helloworld_app/views.py, create a simple view that returns a


"Hello, World!" response:
python

Copy code
from django.http import HttpResponse

def hello_world(request):

return HttpResponse("Hello, World!")

3. Set Up URL Routing: Create a URL configuration for your app. In helloworld_app,
create a file named urls.py if it doesn't exist and add the following:

python

Copy code

from django.urls import path


from .views import hello_world

urlpatterns = [

path('', hello_world, name='hello_world'),

Then, include your app's URLs in the project's URL configuration. Open
helloworld_project/urls.py and modify it:
python
Copy code

from django.contrib import admin

from django.urls import path, include

urlpatterns = [

path('admin/', admin.site.urls),

path('', include('helloworld_app.urls')),

Step 3: Run the Server


1. Apply Migrations: Run the following command to apply any migrations:

bash

Copy code

python manage.py migrate

2. Start the Development Server: Start the server by running:

bash

Copy code

python manage.py runserver

3. View Your Application: Open your web browser and navigate to


http://127.0.0.1:8000/. You should see "Hello, World!" displayed on the page.

That's it! You've created a basic "Hello World" application in Django. If you have any
questions or need further assistance, feel free to ask.

1. Install Django:
o Use pip to install Django.

2. Create a Django Project:


o Use Django’s command-line tools to create a new project.

3. Create a Django App:


o Create an app within the project to handle specific functionality.

2. Developing the Django Web Application

1. Define Models:
o Create models in myapp/models.py to represent the data structure.
2. Create and Apply Migrations:
o Create database tables based on models.

3. Define Views:
o Create views in myapp/views.py to handle HTTP requests.

4. Create Templates:
o Create HTML templates in myapp/templates/myapp/ for rendering data.

5. Define URLs:
o Map URLs to views in myapp/urls.py and myproject/urls.py.

6. Run the Development Server:


o Start Django’s development server to test the application.

Ex:10b simple web application using the Django web framework

Aim:
The aim of developing a simple web application using the Django web framework is to
understand how Django facilitates web development and to evaluate the application's
performance under various loads and scenarios. This involves learning the basics of Django,
implementing a simple web application, and assessing its performance to ensure it meets the
required standards.

Algorithm for Developing and Evaluating a Django Web Application:

Getting Started with Django


1. Installation:

bash

Copy code

pip install django

2. Creating a Django Project:

bash

Copy code

django-admin startproject myproject

cd myproject
3. Running the Development Server:
bash

Copy code

python manage.py runserver

This command starts a development server on http://127.0.0.1:8000/.

4. Creating a Django App:

bash

Copy code

python manage.py startapp myapp


An app is a web application that does something, e.g., a blog or a forum.

5. Defining Models: In myapp/models.py, define your data models using Django's


ORM:
python

Copy code

from django.db import models

class MyModel(models.Model):

name = models.CharField(max_length=100)

description = models.TextField()
6. Making Migrations:

bash

Copy code

python manage.py makemigrations

python manage.py migrate

7. Creating an Admin User:

bash

Copy code

python manage.py createsuperuser

Follow the prompts to create an admin user.


8. Registering Models with Admin: In myapp/admin.py:
python

Copy code

from django.contrib import admin

from .models import MyModel

admin.site.register(MyModel)

9. URL Configuration: In myproject/urls.py:

python
Copy code

from django.contrib import admin

from django.urls import path, include

urlpatterns = [

path('admin/', admin.site.urls),

path('myapp/', include('myapp.urls')),

10. Creating Views: In myapp/views.py:

python

Copy code

from django.shortcuts import render

from .models import MyModel

def my_view(request):
items = MyModel.objects.all()

return render(request, 'myapp/template.html', {'items': items})

11. Templates: Create an HTML template in myapp/templates/myapp/template.html:

html

Copy code
<!DOCTYPE html>
<html>

<head>

<title>My App</title>

</head>

<body>

<h1>Items</h1>

<ul>

{% for item in items %}


<li>{{ item.name }}: {{ item.description }}</li>

{% endfor %}

</ul>

</body>

</html>

12. Running the Server:

bash

Copy code

python manage.py runserver

Visit http://127.0.0.1:8000/myapp/ to see your app in action.

3. Evaluating Performance

1. Load Testing:
o Use tools like Apache JMeter or Locust to simulate traffic and measure how
the application handles load.

o Create test scripts to simulate user interactions and assess performance under
different loads.

2. Profiling and Monitoring:


o Use Django’s built-in profiling tools or third-party tools like Django Debug
Toolbar to analyze performance.

o Monitor application performance and resource usage using tools like New
Relic or Datadog.
3. Database Performance:
o Optimize database queries and use indexing to improve performance.

o Use Django’s query optimization techniques to reduce database load.

4. Stress Testing:
o Identify and test the limits of the application to see how it performs under
extreme conditions.

o Use stress testing tools to simulate high traffic and observe how the
application responds.

5. Scalability Testing:
o Test how the application scales by increasing the number of users or requests.

o Evaluate performance with load balancing and multiple server instances.

Ex.11 Programs on Parallel Computing

Aim:
The aim is to measure and compare the performance of parallel computing techniques (CPU
cores, threads, and multiprocessing) against sequential execution for a specific computational
task. This helps in understanding the benefits and trade-offs of parallel computing in terms of
execution time and resource utilization.

Algorithm:
1. Define the Task
Choose a computationally intensive task suitable for parallelization. Examples include:

 Matrix multiplication

 Numerical integration

 Sorting large datasets

2. Implement Sequential Execution


Create a basic implementation of the chosen task using a sequential approach.

3. Implement Parallel Computing Techniques


Implement the same task using different parallel computing techniques:

 CPU Cores: Use parallelism provided by multi-core CPUs.


 Threads: Use multithreading to parallelize the task within a single process.
 Multiprocessing: Use multiple processes to parallelize the task, potentially across
multiple cores.

4. Measure Performance
Evaluate and compare the performance of each implementation by measuring execution time
and other relevant metrics.

5. Analyze Results
Compare the performance of parallel implementations with the sequential implementation to
understand the benefits of each parallel computing technique.

Detailed Implementation:

1. Define the Task: Matrix Multiplication


Matrix multiplication is a computationally intensive task that benefits from parallel
processing.

2. Sequential Implementation
python

Copy code

import numpy as np

import time

def matrix_multiply_sequential(A, B):

return np.dot(A, B)

# Create random matrices

size = 1000

A = np.random.rand(size, size)

B = np.random.rand(size, size)

# Measure execution time

start_time = time.time()

C = matrix_multiply_sequential(A, B)
end_time = time.time()
print(f"Sequential execution time: {end_time - start_time} seconds")

3. Parallel Implementation Using Threads


python

Copy code

import numpy as np

import time

from threading import Thread

def matrix_multiply_worker(A, B, C, row_start, row_end):

for i in range(row_start, row_end):

C[i, :] = np.dot(A[i, :], B)

def matrix_multiply_threads(A, B, num_threads):

size = A.shape[0]

C = np.zeros((size, size))

threads = []

rows_per_thread = size // num_threads

for i in range(num_threads):

row_start = i * rows_per_thread

row_end = (i + 1) * rows_per_thread if i != num_threads - 1 else size


thread = Thread(target=matrix_multiply_worker, args=(A, B, C, row_start, row_end))

threads.append(thread)
thread.start()

for thread in threads:

thread.join()

return C
# Measure execution time

num_threads = 4

start_time = time.time()

C = matrix_multiply_threads(A, B, num_threads)

end_time = time.time()

print(f"Threads execution time: {end_time - start_time} seconds")

4. Parallel Implementation Using Multiprocessing


python

Copy code

import numpy as np

import time

from multiprocessing import Pool, cpu_count

def matrix_multiply_worker(A_row, B):

return np.dot(A_row, B)

def matrix_multiply_multiprocessing(A, B, num_processes):

size = A.shape[0]

C = np.zeros((size, size))

with Pool(processes=num_processes) as pool:


rows = [A[i, :] for i in range(size)]

results = pool.starmap(matrix_multiply_worker, [(row, B) for row in rows])

C = np.array(results)

return C

# Measure execution time


num_processes = cpu_count()
start_time = time.time()

C = matrix_multiply_multiprocessing(A, B, num_processes)

end_time = time.time()

print(f"Multiprocessing execution time: {end_time - start_time} seconds")

You might also like