Python Lab Program
Python Lab Program
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 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.
o Write a Python script that demonstrates the use of global, local, and nonlocal
variables.
o Write a function that accesses and modifies this global variable using the
global keyword.
o Inside the inner function, use the nonlocal keyword to modify a variable from
the enclosing function’s scope.
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.
# Global variable
def outer_function():
def inner_function():
nonlocal outer_var
inner_function()
modify_global()
outer_function()
# Using pdb for debugging (optional)
output:
Ex:2
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 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.
o Run the program and analyze the output for each argument passing technique.
# Positional Arguments
# Keyword Arguments
# Default Arguments
positional_example(1, 2)
keyword_example(a=1, b=2)
keyword_example(b=2, a=1)
default_example(5)
default_example(5, 15)
variable_length_example(x=10, y=20)
output:
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
Ex:3
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 Use print statements to display how the arguments are unpacked inside the
function.
o Inside the function, unpack the arguments and demonstrate different ways to
use them.
o Run the program and analyze how *args and **kwargs are unpacked and
utilized in each experiment.
def demo_args(*args):
def demo_kwargs(**kwargs):
print(f"{key}: {value}")
args_list = [1, 2, 3, 4]
demo_args_kwargs(*args_list, **kwargs_dict)
output:
Argument 0: 1
Argument 1: 2
Argument 2: 3
Argument 3: 4
a: 10
b: 20
c: 30
Calling demo_args_kwargs(1, 2, 3, x=10, y=20):
Ex:5
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 Assertions are typically used to catch bugs during development and are not
meant to handle runtime errors in production.
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.
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.
o Document the scenarios where assertions catch errors and how they contribute
to debugging.
import math
import time
import numpy as np
def safe_sqrt(x):
return math.sqrt(x)
# Test Experiment 1
try:
except AssertionError as e:
print(f"AssertionError: {e}")
print()
def process_students(students):
print(f"Processing {student['name']}")
# Test Experiment 2
students_data = [
try:
except AssertionError as e:
print(f"AssertionError: {e}")
print()
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)), \
# Test Experiment 3
try:
except AssertionError as e:
print(f"AssertionError: {e}")
print()
if n == 0 or n == 1:
return 1
return n * factorial(n-1)
def test_factorial():
try:
except AssertionError as e:
# Test Experiment 4
print()
result = np.dot(A, B)
return result
# Test Experiment 5
A = np.random.rand(1000, 1000)
B = np.random.rand(1000, 1000)
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}")
start_time = time.time()
output:
3.0
Processing Alice
[1, 2, 3]
[1, 2, 3]
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 Choose problems that can be solved using both recursive and iterative
methods, such as:
o Write Python functions that solve the same problems using iteration.
o Use Python’s time module to measure the execution time of both recursive and
iterative functions.
o Analyze the scenarios where recursion is less or more efficient than iteration.
import time
def factorial_recursive(n):
if n == 0 or n == 1:
return 1
else:
return n * factorial_recursive(n - 1)
def factorial_iterative(n):
result = 1
result *= i
return result
def fibonacci_recursive(n):
if n <= 1:
return n
else:
def fibonacci_iterative(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
def sum_array_recursive(arr):
if len(arr) == 0:
return 0
else:
return arr[0] + sum_array_recursive(arr[1:])
def sum_array_iterative(arr):
total = 0
total += num
return total
start = time.time()
result = func(*args)
end = time.time()
# Test data
n = 30
print("\nSum of array")
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.
o Use the super() function in the __init__ method of the derived classes to
initialize attributes from the base class.
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:
self.name = name
def speak(self):
def describe(self):
class Dog(Animal):
def __init__(self, name, breed):
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):
self.color = color
def speak(self):
return "Meow!"
def describe(self):
print(dog.speak()) # Woof!
print(cat.speak()) # Meow!
# Show that Dog and Cat instances can access methods from Animal
print(isinstance(dog, Animal)) # True
print(dog.speak()) # Woof!
print(cat.speak()) # Meow!
Outout:
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.
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.).
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.
4. Handle Exceptions:
o Implement error handling to manage scenarios such as file not found or
permission issues using try and except blocks.
import os
file.write(content)
print(f"File '{file_name}' created and written to.")
def read_file(file_name):
content = file.read()
print(f"Content of '{file_name}':\n{content}")
file.write(content)
def delete_file(file_name):
"""Delete a file."""
try:
os.remove(file_name)
except FileNotFoundError:
def read_binary_file(file_name):
binary_data = file.read()
def file_operations_demo():
text_file = 'sample.txt'
binary_file = 'sample.bin'
read_file(text_file)
read_file(text_file)
write_binary_file(binary_file, binary_data)
read_binary_file(binary_file)
delete_file(text_file)
delete_file(binary_file)
if __name__ == "__main__":
file_operations_demo()
ouput:
Content of 'sample.txt':
Hello, Python file handling!
Content of 'sample.txt':
Appended line.
Binary data written to 'sample.bin'.
Binary data read from 'sample.bin':
b'x\x03\xff\x00d'
PS C:\Users\sures>
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.
3. Measure Performance:
o Use the time module to measure the time taken to parse large CSV files.
3. Measure Performance:
o Measure the time taken to parse large XML files.
3. Measure Performance:
o Measure the time taken to parse and extract data from large HTML files.
3. Measure Performance:
o Measure the time taken to parse large JSON files.
import csv
import timeit
csv_data = """name,age,city
John,23,New York
Jane,29,Los Angeles
Doe,31,Chicago"""
file.write(csv_data)
reader = csv.DictReader(csvfile)
import timeit
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>"""
file.write(xml_data)
# Function to parse XML
def parse_xml():
tree = ET.parse("test.xml")
root = tree.getroot()
import timeit
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>"""
file.write(html_data)
def parse_html():
with open("test.html", "r") as file:
soup = BeautifulSoup(file, 'html.parser')
table = soup.find('table')
import timeit
json_data = """
"""
def parse_json():
return json.load(file)
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:
bash
Copy code
bash
Copy code
cd helloworld_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',
Copy code
from django.http import HttpResponse
def hello_world(request):
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
urlpatterns = [
Then, include your app's URLs in the project's URL configuration. Open
helloworld_project/urls.py and modify it:
python
Copy code
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('helloworld_app.urls')),
bash
Copy code
bash
Copy code
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.
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.
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.
bash
Copy code
bash
Copy code
cd myproject
3. Running the Development Server:
bash
Copy code
bash
Copy code
Copy code
class MyModel(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
6. Making Migrations:
bash
Copy code
bash
Copy code
Copy code
admin.site.register(MyModel)
python
Copy code
urlpatterns = [
path('admin/', admin.site.urls),
path('myapp/', include('myapp.urls')),
python
Copy code
def my_view(request):
items = MyModel.objects.all()
html
Copy code
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>
<body>
<h1>Items</h1>
<ul>
{% endfor %}
</ul>
</body>
</html>
bash
Copy code
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.
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.
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.
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
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:
2. Sequential Implementation
python
Copy code
import numpy as np
import time
return np.dot(A, B)
size = 1000
A = np.random.rand(size, size)
B = np.random.rand(size, size)
start_time = time.time()
C = matrix_multiply_sequential(A, B)
end_time = time.time()
print(f"Sequential execution time: {end_time - start_time} seconds")
Copy code
import numpy as np
import time
size = A.shape[0]
C = np.zeros((size, size))
threads = []
for i in range(num_threads):
row_start = i * rows_per_thread
threads.append(thread)
thread.start()
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()
Copy code
import numpy as np
import time
return np.dot(A_row, B)
size = A.shape[0]
C = np.zeros((size, size))
C = np.array(results)
return C
C = matrix_multiply_multiprocessing(A, B, num_processes)
end_time = time.time()