Main Python[1]
Main Python[1]
txt" File
# Function to reverse each word in a file
def reverse_words_in_file(filename):
try:
with open(filename, 'r') as file:
lines = file.readlines()
# Connect to MongoDB
client = MongoClient("mongodb://localhost:27017/")
db = client["Library"]
collection = db["Books"]
# Connect to MongoDB
client = MongoClient("mongodb://localhost:27017/")
db = client["Library"]
collection = db["Books"]
Q3 (d) Program to Accept Decimal Number and Print Its Octal and exadecimal
Equivalent
# Function to convert decimal to octal and hexadecimal
def convert_decimal(num):
octal = oct(num)
hexadecimal = hex(num)
print(f"Octal: {octal}, Hexadecimal: {hexadecimal}")
Explanation:
· The program takes a decimal number as input and prints its octal and hexadecimal equivalents
using Python's built-in oct() and hex() functions.
1) Difference Between ArrayList and LinkedList
Feature ArrayList LinkedList
Resizable array (uses an array Doubly linked list (each element points to
Data Structure
internally) both previous and next)
Non-contiguous memory allocation (each
Memory Allocation Contiguous memory allocation
node is stored separately)
Access Time Fast for random access (O(1)) Slower for random access (O(n))
Slow for insertion/deletion in the Faster for insertion/deletion (O(1)) at the ends
Insertion/Deletion
middle (O(n)) or in the middle (if the node is known)
Better for frequent access
Performance Better for frequent insertions and deletions
operations like get()
Suitable for applications that Suitable for applications that require frequent
Usage
require fast random access insertion and deletion
Resizes automatically when No resizing is required, grows as elements are
Resizing
elements exceed capacity added
Underlying Data
Array Doubly Linked List
Structure
Explanation:
· ArrayList is more suitable for scenarios where you need fast access to elements (such as reading
an element by its index). However, insertions and deletions, especially in the middle, can be
costly as elements need to be shifted.
· LinkedList is ideal for applications that require frequent insertions and deletions, particularly in
the middle of the list. However, accessing elements is slower compared to an ArrayList.
· class Person:
· self.name = name
def __hash__(self):
return hash(self.name)
p1 = Person("Alice")
p2 = Person("Alice")
However, we can simulate method overloading using default arguments, *args, or type checking.
calc = Calculator()
print(calc.add(2, 3)) # Output: 5
print(calc.add(2.5, 3.5)) # Output: 6.0
✅ Python Version:
python
CopyEdit
class Animal:
def sound(self):
print("Animal makes a sound")
class Dog(Animal):
def sound(self):
print("Dog barks")
# Runtime Polymorphism
animal = Dog()
animal.sound() # Output: Dog barks
Here, even though animal is declared as an Animal, Python correctly calls the Dog class's sound()
method at runtime. This is run-time polymorphism.
Shallow Cloning and Deep CloningIn Python, cloning or copying refers to creating a duplicate of
an existing object. There are two types of cloning: Shallow Cloning and Deep Cloning.
1. Shallow Cloning:
· Definition: In shallow cloning, a new object is created, but the elements inside the object (like
nested lists or objects) are not copied. Instead, references to the original objects are copied.
· Behavior: When a shallow clone is created, the top-level structure of the object is copied, but
nested objects (objects within the original object) are shared between the original and the
clone. Changes made to nested objects affect both the original and the clone.
· How to create: The copy() method or copy module can be used for shallow cloning.
· Example:
python
CopyEdit
import copy
Explanation: After modifying shallow_copy, the change is reflected in the original object as
well, since both objects point to the same nested list.
2. Deep Cloning:
· Definition: In deep cloning, both the object and all the objects contained within it (recursively)
are copied, meaning that all nested objects are also cloned. No references are shared between
the original and the clone.
· Behavior: Changes made to the nested objects in the deep clone do not affect the original
object and vice versa.
· Example:
python
CopyEdit
import copy
Explanation: In the deep copy, changing the nested list in deep_copy does not affect
original, because the inner lists are copied entirely.
How Deadlock Can Be Avoided in ThreadsDeadlock occurs when two or more threads are
blocked forever because they are waiting for each other to release a resource. To prevent deadlocks, the
following techniques can be used:1. Lock Ordering:Explanation: Ensure that all threads acquire locks
in the same order. If every thread follows the same order for acquiring locks, it prevents circular wait
conditions, which is one of the necessary conditions for deadlock. xample:python
import threading
lock1 = threading.Lock()
lock2 = threading.Lock()
def thread1():
lock1.acquire()
lock2.acquire()
print("Thread 1 is working.")
lock2.release()
lock1.release()
def thread2():
lock1.acquire()
lock2.acquire()
print("Thread 2 is working.")
lock2.release()
lock1.release()In this case, both threads acquire the locks in the same order (lock1
followed by lock2), avoiding deadlock.
2. Lock Timeout:
· Explanation: Another approach is to set a timeout when acquiring a lock. If a thread cannot
acquire the lock within the specified time, it releases any locks it already holds and tries again
later.
· Example:
python
CopyEdit
import threading
import time
lock1 = threading.Lock()
lock2 = threading.Lock()
def thread1():
if lock1.acquire(timeout=1):
print("Thread 1 acquired lock1")
time.sleep(2)
if lock2.acquire(timeout=1):
print("Thread 1 acquired lock2")
lock2.release()
lock1.release()
def thread2():
if lock2.acquire(timeout=1):
print("Thread 2 acquired lock2")
time.sleep(2)
if lock1.acquire(timeout=1):
print("Thread 2 acquired lock1")
lock1.release()
lock2.release()
Example in Python:
· import pickle
# Object to be serialized
data = {'name': 'Alice', 'age': 30, 'city': 'New York'}
# Serialize object to a byte stream (serialize to a file)
with open('data.pkl', 'wb') as f:
pickle.dump(data, f)
# Deserialize the object
with open('data.pkl', 'rb') as f:
loaded_data = pickle.load(f)
print(loaded_data
Explanation:
· Serialization: The dictionary data is serialized using pickle.dump() into a file (data.pkl).
· Deserialization: The file data.pkl is read, and the serialized object is reconstructed using
pickle.load().
Conclusion:
· Shallow Cloning copies references to nested objects, while Deep Cloning copies the entire
object, including nested objects, ensuring no shared references.
· Deadlock in threads can be avoided using techniques like lock ordering, lock timeouts, and
avoiding nested locks.
· Object Serialization is the process of converting an object into a format (like byte streams or
JSON) for storage or transmission, and it is often used in saving objects or in distributed systems.
Python Program to Reverse a Number and Find the Sum of Digits in the Reverse
Number
Here’s a Python program that reverses a number and calculates the sum of digits of the reversed
number.
# Function to reverse a number and calculate the sum of digits of the reversed
number
def reverse_and_sum_digits():
# Take input from user
number = int(input("Enter a number: "))
# Initialize variables
reversed_number = 0
sum_of_digits = 0
Explanation:
1. Input: The program prompts the user to input a number.
2. Reversing the number: The number is reversed by using modulus (%) and integer division (//).
3. Sum of digits: While reversing the number, the program simultaneously adds the digits of the
reversed number to a variable sum_of_digits.
4. Output: Finally, the program prints the reversed number and the sum of digits of the reversed
number.
Example Run:
Enter a number: 1234
Reversed number: 4321
Sum of digits in the reversed number: 10
1. Reuse of Code: If you find yourself writing the same or similar code multiple times across
different scripts, it’s a good practice to place that code into a module.
2. Better Organization: When a program becomes large, it’s important to separate logically
different pieces of functionality into separate modules for better organization and readability.
3. External Libraries: If a functionality you need is available in an external Python library (module),
you can simply import it and use it, saving time and effort.
Suppose you have a task that requires mathematical operations like finding the area of a circle, which
can be reused in multiple programs. You can create a module for this functionality.
# circle_operations.py
import math
def area_of_circle(radius):
return math.pi * (radius ** 2)
# main_program.py
import circle_operations
Justification:
· Using a module here makes your code reusable, and you only need to write the function
area_of_circle() once.
· You can use this module in multiple programs without duplicating the same logic.
· It keeps the code organized and easier to maintain as your project grows.
Example of Decorator:
# Basic decorator function
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
# Function to be decorated
@my_decorator
def say_hello():
print("Hello!")
Explanation:
1. Decorator Function: my_decorator is the decorator function. It takes a function func as an
argument and defines a nested function wrapper(). The wrapper() function adds some extra
behavior before and after calling func().
2. Using the Decorator: The @my_decorator syntax is used to apply the decorator to the
say_hello() function. This makes say_hello() call wrapper() instead, which adds extra
behavior while calling say_hello().
Output:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
Decorators are useful for tasks like logging, access control, memoization, and more.
return avg
Explanation:
1. Input: The user is prompted to enter numbers separated by spaces.
2. Processing: The input string is split into individual elements, and each element is converted to
an integer.
3. Calculation: The sum of the numbers is divided by the total count of numbers to find the
average.
Example Run:
Enter numbers separated by space: 10 20 30 40
The average of the entered numbers is: 25.0
Conclusion:
· Shallow and Deep Cloning: These techniques are important for understanding object behavior
in Python. Shallow cloning only copies references to nested objects, whereas deep cloning
creates independent copies of all objects.
· Using Modules: Modules help in organizing and reusing code. You can use a module when you
want to reuse logic across different programs or to keep code organized.
· Python Program to Reverse a Number and Find the Sum of Digits in the
Reverse Number
Here's the Python program that reverses the number entered by the user and calculates the sum of
digits in the reversed number:
# Function to reverse a number and calculate the sum of digits of the reversed
number
def reverse_and_sum_digits():
# Take input from the user
number = int(input("Enter a number: "))
# Initialize variables
reversed_number = 0
sum_of_digits = 0
Explanation:
1. Input: The program prompts the user to input a number.
2. Reversing the number: The number is reversed by using modulus (%) and integer division (//).
3. Sum of digits: While reversing the number, the program simultaneously adds the digits of the
reversed number to a variable sum_of_digits.
4. Output: Finally, the program prints the reversed number and the sum of digits of the reversed
number.
Example Run:
Enter a number: 1234
Reversed number: 4321
Sum of digits in the reversed number: 10
1. Code Reusability: If you have a set of related functions or variables that you use frequently
across different programs, it is a good idea to place them into a module.
2. Organization: As your codebase grows, it’s important to break down your code into smaller,
more manageable files. Using modules helps you organize your code logically and keeps it more
readable.
3. Separation of Concerns: If your program does multiple things, like handling user input,
performing calculations, and writing output, it's beneficial to separate these tasks into different
modules.
Example:Suppose you have a program that deals with geometric calculations (like finding the area of
different shapes). You can create a module to handle these calculations, so you can reuse it in multiple
programs without rewriting the code.
# geometry.py
import math
def area_of_circle(radius):
return math.pi * (radius ** 2)
def area_of_square(side):
return side * side
Using the Module in Another Program (main.py):
# main.py
import geometry
radius = float(input("Enter the radius of the circle: "))
area_circle = geometry.area_of_circle(radius)
print(f"The area of the circle is: {area_circle}")
side = float(input("Enter the side of the square: "))
area_square = geometry.area_of_square(side)
print(f"The area of the square is: {area_square}")
def wrapper():
# Function to be decorated
@my_decorator
def say_hello():
print("Hello, World!")
Explanation:
1. my_decorator: This is the decorator function. It takes a function func as an argument.
2. wrapper: This is a new function that wraps around the original func to add extra behavior
before and after the function call.
4. Result: When say_hello() is called, the output includes the additional behavior from the
decorator.
Output:
Before function call.
Hello, World!
After function call.
b) Write a Function average() Which Will Return the Average of the Numbers
Inputted by the User
Here’s a Python program that defines a function average() to calculate the average of numbers
inputted by the user:
return avg
Explanation:
1. Input: The user is asked to enter a series of numbers separated by spaces.
2. Processing: The split() method splits the input into a list of strings, which are then converted
to integers using a list comprehension.
3. Calculation: The sum() function calculates the total sum of the numbers, and the len()
function gives the count of numbers. The average is computed by dividing the sum by the count.
4. Output: The function returns and prints the average of the numbers.
Example Run:
Enter numbers separated by spaces: 10 20 30 40 50
The average of the entered numbers is: 30.0
Conclusion:
· Reverse and Sum of Digits: The program reverses the number and calculates the sum of its
digits.
· Modules: Modules are useful for organizing and reusing code across different programs.
Here’s the Python program that uses regular expressions to validate the PAN card number:
import re
# Function to validate PAN card number
def validate_pan(pan):
# Regular expression for validating PAN card number
pattern = r'^[A-Z]{5}[0-9]{4}[A-Z]{1}$'
# Check if the PAN matches the pattern
if re.match(pattern, pan):
return True
else:
return False
# Accept input from user
pan_number = input("Enter PAN card number: ")
# Validate the PAN number
if validate_pan(pan_number):
print("PAN card number is valid.")
else:
print("Invalid PAN card number.")
class Car:
# Constructor
def __init__(self, make, model):
self.make = make
self.model = model
print(f"Car {self.make} {self.model} is created.")
# Destructor
def __del__(self):
print(f"Car {self.make} {self.model} is destroyed.")
Example:
class Animal:
# Method in parent class
def speak(self):
print("Animal is making a sound.")
class Dog(Animal):
# Overriding the speak method in subclass
def speak(self):
super().speak() # Call the parent class method
print("Dog is barking.")
Example Output:
Animal is making a sound.
Dog is barking.
Python Program to Validate a Strong PasswordA strong password should meet the following
conditions:At least one uppercase letter.At least one lowercase letter.At least one digit.At least one
special character.Minimum 8 characters in length.
import re
# Function to validate strong password
def validate_password(password):
# Regular expression pattern to validate the password
pattern = r'^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?
&]{8,}$'
# Check if the password matches the pattern
if re.match(pattern, password):
return True
else:
return False
# Accept input from user
password = input("Enter a password: ")
# Validate the password
if validate_password(password):
print("The password is strong.")
else:
print("The password is weak. It must include at least one capital letter,
one numeric character, and one special character.")
Let's compute the total price and maximum profit from the above data using Python code.
import pandas as pd
Output:
Total Price of All Products: 100000
Maximum Profit from Given Products: 5000
b) Create a 6x6 2D NumPy Array and Retrieve Bottom-Right Corner 2x2 Array
You can create a 6x6 NumPy array and retrieve the bottom-right 2x2 subarray using the following code:
import numpy as np
OR: Create a Series from NumPy Array and Find Max and Mean of Unique Items
To create a Pandas Series from a NumPy array and then compute the maximum and mean of the unique
items, you can use the following code:
import pandas as pd
import numpy as np
Explanation:
· pd.Series(arr) converts the NumPy array arr into a Pandas Series.
· max() and mean() are used to calculate the maximum and mean of the unique items.
Output:
Unique items: [1 2 3 4 5]
Max value of unique items: 5
Mean value of unique items: 3.0
· NumPy Array to Series: A NumPy array can also be directly converted into a Pandas Series.
· Dictionary to Series: The keys of the dictionary become the index of the Series, and the values
become the corresponding elements.
a) Shallow Copy with Suitable Example
A shallow copy in Python refers to creating a new collection (such as a list, dictionary, or set) that
contains references to the original objects. However, if the original objects contain references to other
objects (like nested lists or dictionaries), only the references to those nested objects are copied, not the
nested objects themselves. This means that if you modify a nested object, it will reflect in both the
original and the copied collection.
Python provides several ways to make a shallow copy, such as using the copy() method or the copy
module’s copy() function.
Output:
Original List: [1, 2, [100, 4]]
Shallow Copy: [1, 2, [100, 4]]
In this case, the change in the nested list in shallow_copy is also reflected in original_list,
because the reference to the nested list is shared between both. The shallow copy only copied the outer
list, not the nested objects inside it.
import pymongo
# Connect to MongoDB
client = pymongo.MongoClient("mongodb://localhost:27017/")
# Create/select database
db = client["learning_database"]
# Create/select collection
learners_collection = db["learners"]
1. {"name": 1, "_id": 0} to retrieve only the name field from each document, excluding the
default _id field.
Output:
List of Learners' Names:
John Doe
Jane Smith
Mark Johnson
Emily Davis
· Shallow Copy: A shallow copy creates a new object but does not recursively copy nested
objects. Modifying nested objects affects both the original and the copied collection.
end_time = time.time()
## Q1)
### a) Write python program to reverse a number and find the sum of digits in reverse number
prompt the user for input.
```python
def reverse_and_sum():
num = input("Enter a number: ")
reversed_num = num[::-1]
sum_digits = sum(int(digit) for digit in reversed_num)
reverse_and_sum()
```
### b) How would you determine when to use a module in your code. Justify with suitable example.
You should use a module when:
1. You want to organize related code into reusable components
2. You need functionality that's already implemented in existing modules
3. You want to avoid code duplication
4. You need to separate concerns in your application
Example justification:
When working with dates in Python, instead of implementing all date calculations yourself, you should
use the `datetime` module:
import datetime
# Without module (bad practice)
# You'd have to implement all date logic yourself
# With module (good practice)
today = datetime.date.today()
next_week = today + datetime.timedelta(days=7)
print(f"Today: {today}, Next week: {next_week}")
```
## Q2)
### a) Explain Decorator concept with suitable example.
Decorators are a design pattern in Python that allows you to modify the functionality of a function
without changing its source code. They are functions that take another function as an argument and
extend its behavior.
Example:
```python
def uppercase_decorator(func):
def wrapper():
result = func()
return result.upper()
return wrapper
@uppercase_decorator
def say_hello():
return "hello world"
### b) Write a function average() which will return the average of the numbers inputted by the user.
```python
def average():
numbers = []
while True:
user_input = input("Enter a number (or 'done' to finish): ")
if user_input.lower() == 'done':
break
try:
numbers.append(float(user_input))
except ValueError:
print("Please enter a valid number or 'done' to finish.")
if not numbers:
return 0
return sum(numbers) / len(numbers)
### b) Write a Python program that defines a custom exception that takes user input. If the user
enters a negative number, raise the custom exception with an appropriate error message. Implement
exception handling to catch and handle this custom exception.
```python
class NegativeNumberError(Exception):
pass
def check_positive():
try:
num = float(input("Enter a positive number: "))
if num < 0:
raise NegativeNumberError("Negative numbers are not allowed!")
print(f"You entered: {num}")
except NegativeNumberError as e:
print(f"Error: {e}")
except ValueError:
print("Please enter a valid number.")
check_positive()
```
### OR
### a) Write a Python program that creates two threads. One thread should print even numbers from
2 to 10 & the other should print odd numbers from 1 to 9. Ensure that the threads run concurrently &
use Synchronization.
```python
import threading
lock = threading.Lock()
def print_even():
with lock:
for num in range(2, 11, 2):
print(f"Even: {num}")
def print_odd():
with lock:
for num in range(1, 10, 2):
print(f"Odd: {num}")
t1 = threading.Thread(target=print_even)
t2 = threading.Thread(target=print_odd)
t1.start()
t2.start()
t1.join()
t2.join()
```
### b) What is file in Python? Write a python program that reads a text file named "sample.txt" and
prints its contents to the console.
In Python, a file is an object that allows you to work with files on your filesystem. It can be used to read,
write, or append data.
```python
def read_file():
try:
with open("sample.txt", "r") as file:
contents = file.read()
print(contents)
except FileNotFoundError:
print("File 'sample.txt' not found.")
except IOError:
print("Error reading the file.")
read_file()
```
### a) Write a Python Program using MongoDB database to create a collection "Badminton
Tournaments" with fields (player-id, p-name, age, phone no) and display all registration.
```python
from pymongo import MongoClient
def manage_badminton_tournament():
client = MongoClient('mongodb://localhost:27017/')
db = client['tournament_db']
collection = db['Badminton_Tournaments']
# Insert sample data
collection.insert_many([
{"player-id": "P001", "p-name": "Player One", "age": 25, "phone no": "1234567890"},
{"player-id": "P002", "p-name": "Player Two", "age": 28, "phone no": "9876543210"}
])
# Display all registrations
print("All Registrations:")
for player in collection.find():
print(player)
manage_badminton_tournament()
```
### b) How to create a series from a list, numpy array and dictionary? Also demonstrate how to create
a series with labeled index.
```python
import pandas as pd
import numpy as np
# From list
list_data = [10, 20, 30, 40]
series_from_list = pd.Series(list_data)
print("From list:")
print(series_from_list)
# From numpy array
np_array = np.array([1.1, 2.2, 3.3, 4.4])
series_from_array = pd.Series(np_array)
print("\nFrom numpy array:")
print(series_from_array)
# From dictionary
dict_data = {'a': 100, 'b': 200, 'c': 300}
series_from_dict = pd.Series(dict_data)
print("\nFrom dictionary:")
print(series_from_dict)
# With labeled index
labeled_series = pd.Series([5, 10, 15, 20], index=['A', 'B', 'C', 'D'])
print("\nWith labeled index:")
print(labeled_series)
```