0% found this document useful (0 votes)
3 views44 pages

Python Long Question Answer

Uploaded by

Tridib Bhunia
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
3 views44 pages

Python Long Question Answer

Uploaded by

Tridib Bhunia
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 44

LONG QUESTION

1. (a)List various types of operators in Python and write any 4 types of operators.
Arithmetic Operators: Arithmetic operators are used to perform mathematical operations like
addition, subtraction, multiplication, division, etc.
• Example

x = 10
y=3 OUTPUT:
print(x + y) # Addition 13
print(x - y) # Subtraction 7
print(x * y) # Multiplication 30
print(x / y) # Division 3.3333333333333335

Comparison (Relational) Operators: Comparison operators are used to compare two values or
operands and return True or False based on the comparison.

• Example:
a = 10
b = 20 OUTPUT:
print(a == b) # Equal to False
print(a != b) # Not equal to True
print(a > b) # Greater than False
print(a < b) # Less than True

Assignment Operators: Assignment operators are used to assign values to variables.


• Example:
x = 10 # Assigns 10 to x
y += 5 # Equivalent to y = y + 5
z *= 2 # Equivalent to z = z * 2
Logical Operators: Logical operators are used to combine conditional statements and return True
or False.
• Example:
a = True
b = False OUTPUT:
print(a and b) #Logical AND False
True
print(a or b) # Logical OR
False
print(not a) # Logical NOT

Bitwise Operators: Bitwise operators perform operations on binary representations of integers.

• Example:

x = 10 # Assigns 10 to x
y += 5 # Equivalent to y = y + 5
z *= 2 # Equivalent to z = z * 2
Logical Operators: Logical operators are used to combine conditional statements and return True
or False.
• Example:
a = True
b = False OUTPUT:
print(a and b) #Logical AND False
True
print(a or b) # Logical OR
False
print(not a) # Logical NOT
Bitwise Operators: Bitwise operators perform operations on binary representations of integers.
• Example:

x = 10 # Binary: 1010 OUTPUT:


y = 4 # Binary: 0100 0
print(x & y) # Bitwise AND: 0000 (0) 14
print(x | y) # Bitwise OR: 1110 (14) 14
print(x ^ y) # Bitwise XOR: 1110 (14)

Membership Operators: Membership operators are used to test if a sequence is present in an


object.
• Example:

my_list = [1, 2, 3, 4, 5] OUTPUT:


print(3 in my_list) # True True
print(6 not in my_list) # True True

Identity Operators: Identity operators are used to compare the memory locations of two objects.

• Example:

x = [1, 2, 3] OUTPUT:
y = [1, 2, 3] False
print(x is y) # False True
print(x is not y) # True

Unary Operators: Unary operators are used to perform operations on a single operand.
• Example:
x = 10
print(-x) # Unary minus OUTPUT:
print(+x) # Unary plus -10
10

( b ) Outline with an example the assignment and bitwise operators supported in


Python.
Assignment Operators:
Assignment Operator (=):
• Assigns the value on the right to the variable on the left.
• Example
x= 5
Addition Assignment Operator (+=):
• Adds the value on the right to the variable on the left and assigns the result to the variable on
the left.
• Example
x += 3 # Equivalent to x = x + 3
Subtraction Assignment Operator (-=):
• Subtracts the value on the right from the variable on the left and assigns the result to
the variable on the left.
• Example
y -= 2 # Equivalent to y = y – 2
Multiplication Assignment Operator (*=):
• Multiplies the variable on the left by the value on the right and assigns the result to the
variable on the left.
• Example

z *= 4 # Equivalent to z = z * 4
Bitwise Operators:
Bitwise AND (&):
• Performs a bitwise AND operation on the binary representations of two integers.
• Example

result = 7 & 3 # Binary: 0111 & 0011 = 0011 (3)


Bitwise OR (|):
Performs a bitwise OR operation on the binary representations of two integers.
Example
result = 7 | 3 # Binary: 0111 | 0011 = 0111 (7)
Bitwise XOR (^):
• Performs a bitwise XOR (exclusive OR) operation on the binary representations of two
integers.
• Example
result = 7 ^ 3 # Binary: 0111 ^ 0011 = 0100 (4)
Bitwise Left Shift (<<):
• Shifts the bits of the left operand to the left by the number of positions specified by the
right operand.
• Example:
result = 5 << 2 # Binary: 101 << 2 = 10100 (20)
Bitwise Right Shift (>>):
• Shifts the bits of the left operand to the right by the number of positions specified by
the right operand.
• Example:
result = 5 >> 2 # Binary: 101 >> 2 = 1 (1)

(c) What is the difference between = = and is operator in Python?


==Operator (Equality Operator):
• The ==operator is used to compare the values of two objects to determine if they are
equal.
• It returns Trueif the values of the two objects are equal, and Falseotherwise.
• Example
x = [1, 2, 3]
y = [1, 2, 3]
print(x == y) # Output: True
isOperator (Identity Operator):
• The isoperator is used to compare the memory locations (identities) of two objects to
determine if they are the same object.
• It returns Trueif the two objects refer to the same memory location, and False
otherwise.
• Example
x = [1, 2, 3]
y = [1, 2, 3]
print(x is y) # Output: False
• The ==operator checks for equality of values.
• The isoperator checks for identity, i.e., whether two objects refer to the same
memory location.

2. (a) Define function? Write its syntax.


In programming, a function is a block of organized, reusable code that performs a specific task.
Functions provide modularity to programs, making them easier to understand, debug, and maintain.
They accept input arguments, perform operations based on those inputs, and optionally return a
result.Here's the syntax of a function in Python:
def function_name(parameter1,
parameter2, ...): """
Docstring: Description of the function
(optional) """
# Function body: Code block that defines the functionality of
the function # Statements
return expression # (optional) Return statement, used to return a value from the function
Explanation of each part:
def: Keyword used to define a function.
function_name: Name of the function, which should be descriptive of the task the
function performs.
(parameter1, parameter2, ...): Optional parameters (also known as arguments) that the
function accepts. These parameters are placeholders for the values that will be passed to
the function when it is called.
:: Colon used to indicate the start of the function body.
"""Docstring""": (Optional) Docstring, which provides documentation about the purpose
and usage of the function. It is enclosed within triple quotes.
• Function body: Block of code that defines the functionality of the function. It may include any
number of statements to perform specific tasks.
• return expression: (Optional) Return statement, used to return a value from the function. The
function terminates and returns the value specified by the expression. If no return statement
is provided, the function returns None by default.
Example of a simple function that adds two numbers:
def add_numbers(x,
y): """
This function adds two numbers and returns
the result. ""
result = x + y
return result

# Calling the function and storing the result in a


variable sum_result = add_numbers(3, 5)
print("Sum:", sum_result) # Output: Sum: 8

(b) What are formal and actual arguments.


Formal Arguments:
• Formal arguments are the placeholders defined in the function definition to receive
values when the function is called.
• These are the parameter names listed inside the parentheses in the function definition.
• Formal arguments act as local variables within the function's scope.
• Formal arguments are used to specify what inputs the function expects to receive.
• Example
def greet(name):
print("Hello,",
name)

# Here, 'name' is a formal argument of the 'greet' function


Actual Arguments:
• Actual arguments are the values supplied to the function when it is called.
• These are the values passed inside the parentheses when calling the function.
• Actual arguments can be of various types, such as literals, variables, expressions, or
function calls.
• Actual arguments are used to provide the necessary data to the function for processing.
• Example:
greet("Alice")
# Here, "Alice" is an actual argument passed to the 'greet' function
In summary:
• Formal arguments are the parameters defined in the function definition.
• Actual arguments are the values passed to the function when calling it.

(b) Write functions to do all arithmetic operations.

Addition:
def addition(x,
y): return x + y
Subtraction:
def subtraction(x,
y): return x – y

Multiplication:
def multiplication(x, y):
return x * y
Division:
def division(x, y):
if y != 0:
return x / y
else:
return "Error: Division by zero"

Floor Division:
def floor_division(x, y):
if y != 0:
return x // y
else:
return "Error: Division by zero"

Modulus (Remainder):
def modulus(x, y):
if y != 0:
return x % y
else:
return "Error: Division by zero"
Exponentiation:
def exponentiation(x, y):
return x ** y
These functions can be used to perform various arithmetic operations by passing
appropriate arguments. For example:

print(addition(5, 3)) # Output: 8


print(subtraction(5, 3)) # Output: 2
print(multiplication(5, 3)) # Output: 15
print(division(5, 3)) # Output: 1.6666666666666667
print(floor_division(5, 3)) # Output: 1
print(modulus(5, 3)) # Output: 2
print(exponentiation(5, 3)) # Output: 125

(c) Give two examples of built-in function with syntax in python.


len()function:

• Syntax: len(iterable)
• Description: Returns the number of items (length) in an iterable object such as a list, tuple,
string, dictionary, or set.
• Example
my_list = [1, 2, 3, 4, 5]
length = len(my_list)
print("Length of the list:", length)
# Output: Length of the list: 5
max()function:

• Syntax: max(iterable, *[, default=obj, key=func])or max(arg1, arg2,*args[, key=func])


• Description: Returns the maximum value from an iterable or a series of arguments.
Optionally, you can specify a default value and a key function for custom comparison.
• Example
my_tuple = (10, 20, 5, 30, 15)
max_value = max(my_tuple)
print("Maximum value:", max_value) # Output: Maximum value: 30

3. (a)Explain in detail about Control flow structures in python.


Conditional Statements:
Conditional statements allow you to execute different blocks of code based on whether a
condition is true or false.
The primary conditional statement in Python is the ifstatement, which can be extended with
elif (short for "else if") and else clauses.

• Example:

x = 10
if x > 0:
print("x is
positive") elif x == 0:
print("x is
zero") else:
print("x is negative")
Looping Statements:
• Looping statements allow you to execute a block of code repeatedly as long as a
certain condition is met.
• Python provides two main types of loops: forloops and whileloops.
• forloops iterate over a sequence (such as lists, tuples, strings, or ranges) and
execute a block of code for each element in the sequence.
• Example of a forloop

for i in range(5):
print(i)
• whileloops continue to execute a block of code as long as a specified condition
is true.
• Example of a whileloop

x=0
while x < 5:
print(x)
x += 1
Control Statements:
• Control statements allow you to alter the flow of execution within loops and conditional
statements.
• Python provides break, continue, and passstatements for this purpose.
• The breakstatement terminates the loop it is contained within prematurely.
• The continuestatement skips the rest of the loop's body for the current iteration and
continues with the next iteration.
• The continuestatement skips the rest of the loop's body for the current iteration and continues with
the next iteration.
• The passstatement is a no-operation placeholder that is used when a statement is syntactically
required but you want to do nothing.
Example
for i in
range(10):
if i == 3:
continue
elif i == 7:
break
else:
pass
print(i)
Exception Handling:
• Exception handling allows you to handle errors and exceptions that may occur
during the execution of a program.
• Python provides try, except, else, and finallyblocks for exception handling.
• Example:
try:
result = 10 / 0
except ZeroDivisionError:
print("Error: Division by
zero")
else:
print("No exception occurred")
finally:
print("Cleanup code")

(b)Write a Python program to print prime number series up to N.


def
is_prime(num):
if num <= 1:
return
False elif
num == 2:
return True
elif num % 2 == 0:
return
False else:
for i in range(3, int(num**0.5) +
1, 2): if num % i == 0:
return
False return
True
def print_prime_series(N): prime_series = []
for num in range(2, N +
1): if
is_prime(num):
prime_series.append(num)
return prime_series
# Input from the user
OUTPUT:
N = int(input("Enter the value of N: "))
Enter the value of N: 9
# Printing prime number series Prime numbers up to 9 are:
up to N print("Prime numbers up [2, 3, 5, 7]
to", N, "are:")
print(print_prime_series(N))

4. (a)Explain the purpose of loop structure in a programming language.


1. Repetition: Loops allow you to repeat a block of code multiple times without having to write the same
code over and over again. This helps in reducing redundancy and makes the code more concise.
2. Automation: Loops automate repetitive tasks by iterating over a sequence of statements or
processing elements of a collection (such as lists, tuples, or strings). This saves time and effort,
especially when dealing with large datasets or performing batch operations.
3. Efficiency: By using loops, you can perform operations on a large number of items efficiently. Instead
of manually performing the same operation on each item individually, you can write a loop to process
all items in one go.
4. Dynamic behavior: Loops allow you to execute a block of code conditionally based on certain
conditions. This dynamic behavior enables your program to respond to changing circumstances and
make decisions based on real-time data.
5. Flexibility: Loops provide flexibility in controlling the flow of execution within a program. You can use
control statements such as break, continue and pass to later the behavior of loops based on
specific conditions.
6. Iterative algorithms: Many algorithms, such as searching, sorting, and data processing algorithms,
rely on iterative processes. Loops provide a natural way to implement these algorithms in code.

(b)Describe the syntax and semantics of any two loop structures provided by Python.
forloop:
• Syntax:
for item in iterable:
# Code block to be executed for each item
• Semantics:
• The forloop iterates over each item in the given iterable (such as lists, tuples, strings, or
ranges).
• In each iteration, the loop variable itemis assigned the value of the current item in the iterable.
• The code block inside the loop is executed for each item in the iterable.
• After processing all items in the iterable, the loop terminates.
• Example:

numbers = [1, 2, 3, 4, 5]
for num in
numbers:
print(num)
Output:
1
2
3
4
whileloop:

• Syntax

while condition:
# Code block to be executed as long as condition is true
• Semantics:
• The whileloop repeatedly executes a block of code as long as the specified condition is
true.
• Before each iteration, the condition is evaluated. If it evaluates to True, the code block
inside the loop is executed. If it evaluates to False, the loop terminates.
• The code block inside the loop may contain statements that modify the variables involved in
the loop condition.
• If the loop condition never becomes False, the loop continues indefinitely, resulting in
an infinite loop.
• Example:
count = 0
while count
< 5:
print(coun
t)
count += 1
Output:
0
1
2
3
4

(c)Write a python program to print the sum of the series: 1+1/2 2 +1/3 3 +……+1/n n
def series_sum(n):
sum_series = 0
for i in range(1, n + 1):
sum_series += 1 / (i * i)
return sum_series

# Input: value of n
n = int(input("Enter the value of n: "))

# Calculate the sum of the series Output:-


result = series_sum(n) Enter the value of n: 5
The sum of the series is: 1.4636111111111112
# Print the result
print(f"The sum of the series is: {result}")

5. (a) What is recursive function?


A recursive function is a function that calls itself either directly or indirectly in order to solve a problem.
In other words, it's a function that repeats or recurses its own behavior. Recursion is a fundamental
concept in computer science and is commonly used to solve problems that can be broken down into
smaller, similar subproblems.
Key characteristics of recursive functions include:
1. BaseCase : A terminating condition that indicates when the recursion should stop.
Without a base case, the recursive function would continue to call itself indefinitely, resulting in a
stack overflow error.

2. Recursive Case: A set of instructions that break down the problem into smaller, similar
subproblems and make recursive calls to solve them. Each recursive call works on a smaller
instance of the original problem until it reaches the base case.

3. Indirect Recursion: When a function calls another function, which in turn calls the original
function, it forms indirect recursion. This pattern can be used to solve problems that cannot be
easily solved using direct recursion alone
Recursive functions are commonly used to solve problems that exhibit a recursive structure, such as
tree traversal, factorial computation, Fibonacci sequence generation, and sorting algorithms like
quicksort and mergesort.
Here's an example of a recursive function to compute the factorial of a non-negative integer:
def factorial(n):
if n == 0:
return 1 # Base case:
factorial of 0 is 1 else:
return n * factorial(n - 1) # Recursive case: n! = n * (n-1)!

(b) Explain lambda function.


The syntax of a lambda function is as follows:
lambda arguments: expression
• lambda: Keyword used to define a lambda function.
• arguments: Comma-separated list of input parameters to the function. Similar to the parameters
in a regular function.
• expression: Single expression or calculation that the lambda function evaluates and returns as
its result.

Lambda functions are typically used when you need a simple function for a short period of time,
often as an argument to higher-order functions (functions that take other functions as arguments),
such as map(), filter(), and sorted().
Here's an example of a lambda function that calculates the square of a number
square = lambda x: x ** 2
You can then use this lambda function just like any other function:.
print(square(5)) # Output: 25
Lambda functions can also take multiple arguments:
add = lambda x, y: x + y
print(add(3, 5)) #
Output: 8

(c)Write recursive function to find factorial of a number.


# Factorial of a number using recursion
def recur_factorial(n):
if n == 1:
return n
else:
return n*recur_factorial(n-1)
num = 5
# check if the number is negative
if num < 0:
print("Sorry, factorial does not exist for
negative numbers") elif num == 0:
print("The factorial of
0 is 1") else:
print("The factorial of", num, "is", recur_factorial(num))

(d)Write recursive function to find out the GCD of two numbers.


def gcd(a, b): if b == 0:
ret
urn a
else:
return gcd(b, a % b)

# Example usage:
num1 =2
num2 =4
print("GCD of", num1, "and", num2, "is:", gcd(num1, num2))

6. (a) Write a Python program that counts the number of occurrences of the character
in the given string. Provide two implementations: recursive and iterative.
1. Recursive Implementation:
def count_occurrences_recursive(string, char):

if not string: # Base case: if string is


empty, return 0 return 0
elif string[0] == char: # If first character matches the char
return 1 + count_occurrences_recursive(string[1:], char) # Count and
recurse for the rest of the string
else:
return count_occurrences_recursive(string[1:], char) # Recurse for the rest of the string

# Input string and character from the


user input_string = input("Enter a
string: ")
input_char = input("Enter a character to count occurrences: ")

# Counting occurrences of the character in the string


using recursion occurrences =
count_occurrences_recursive(input_string,
input_char)
print("Number of occurrences of", input_char, "in the string (using recursion):",
2. Iterative Implementation:
occurrences)
def
count_occurrences_iterative(stri
ng, char): count = 0
for c in string:
if c == char:
count
+= 1
return
count
# Input string and character from the
user input_string = input("Enter a
string: ")
input_char = input("Enter a character to count occurrences: ")
# Counting occurrences of the character in the string
using iteration occurrences =
count_occurrences_iterative(input_string, input_char)
print("Number of occurrences of", input_char, "in the string (using iteration):", occurrences)
def
count_occurrences_iterative(stri
ng, char): count = 0
for c in string:
if c == char:
count
+= 1
return
count
# Input string and character from the
user input_string = input("Enter a
string: ")
input_char = input("Enter a character to count occurrences: ")

# Counting occurrences of the character in the string


using iteration occurrences =
count_occurrences_iterative(input_string, input_char)
print("Number of occurrences of", input_char, "in the string (using iteration):", occurrences)

(b) Write a python program to retrieve strings starting with m and having 5 characters
def retrieve_strings(strings): result = []
for s in strings:
if len(s) == 5 and s.startswith('m'):
result.append(s)
return result

# Example list of strings


strings = ["apple", "mango", "melon", "march", "dog", "mouse"]

# Retrieve strings starting with 'm' and having 5 OUTPUT:


characters filtered_strings = retrieve_strings(strings) Strings starting with 'm' and having 5
# Print the result characters:
print("Strings starting with 'm' and having 5
characters:") print(filtered_strings) ['mango', 'melon', 'march', 'mouse']
7. (a) Differentiate Abstract class and interface with example.
Abstract Class:
• An abstract class in Python is a class that cannot be instantiated on its own and is meant to be
subclassed. It may contain one or more abstract methods, which are methods that are
declared but not implemented in the abstract class itself. Subclasses of an abstract class must
provide implementations for all the abstract methods.
• Abstract classes can also contain concrete methods, which have implementations. Abstract
classes are typically used when you want to define a common interface for a set of related
classes, but you want to enforce certain methods to be implemented by all subclasses.
• Example
from abc import ABC, abstractmethod
class Shape(ABC): # Abstract class
@abstractmethod
def area(self): # Abstract method
pass
@abstractmethod
def perimeter(self): # Abstract
method pass
class Circle(Shape):
def init (self, radius):
self.radius = radius
def area(self): # Implementation of abstract
method return 3.14 * self.radius *
self.radius
def perimeter(self): # Implementation of abstract
method return 2 * 3.14 * self.radius
circle = Circle(5)

print("Area of circle:", circle.area()) # Output: Area of circle: 78.5

Interface:
•Python does not have a built-in interface keyword like some other programming
languages. However, interfaces can be simulated using abstract classes with all methods
declared as abstract. In Python, interfaces are essentially abstract classes that contain only
abstract methods (i.e., methods with no implementation).
• Interfaces define a contract that classes must adhere to. Any class that implements
an interface must provide concrete implementations for all the methods declared in
the interface.
• Example
from abc import ABC, abstractmethod
class Printable(ABC): # Interface (abstract class with abstract methods only)
@abstractmethod
def print_info(self): # Abstract method pass
class
Document(Printable
): def init (self,
content):
self.content = content
def print_info(self): # Implementation of abstract
method print("Document content:",
self.content)

doc = Document("This is a document")


doc.print_info() # Output: Document content: This is a document
• Abstract classes can have both abstract and concrete methods, while interfaces contain only
abstract methods.
• Subclasses of an abstract class must implement all abstract methods, while classes
implementing an interface must provide implementations for all interface methods.
• Abstract classes are used to define a common interface for a set of related classes, while
interfaces define a contract that classes must adhere to.

(b)Explain built-in class attributes in a python class.


1. doc : This attribute contains the docstring (documentation string) associated with the class.
It provides information about the purpose and usage of the class.
2. name : This attribute contains the name of the class as a string. It is useful for obtaining the
name of the class programmatically.

3. module : This attribute contains the name of the module in which the class is defined. It is
useful for obtaining information about the module containing the class.

4. bases : This attribute contains a tuple of the base classes (parent classes) of the class. It
provides information about the inheritance hierarchy of the class.

5. dict : This attribute contains a dictionary that holds the namespace of the class. It stores all the
attributes (both class attributes and instance attributes) defined in the class.

6. class : This attribute contains a reference to the class itself. It is used to access class methods
and class attributes from within the class.

Here's an example demonstrating the use of built-in class attributes in Python:


class MyClass:
"""This is a sample class."""

def init (self, value):


self.value = value

# Accessing built-in class attributes


print("Docstring:", MyClass. doc )
print("Class name:", MyClass. name )
print("Module:", MyClass. module )
print("Base classes:", MyClass. bases )
print("Namespace:", MyClass. dict )
print("Class reference:", MyClass. class
Output:

Docstring: This is a sample class.

Class name: MyClass


Module: main
Base classes: (<class 'object'>,)
Namespace: {' module ': ' main ', ' doc ': 'This is a sample class.', ' init ': <function
MyClass. init at 0x7f6a8073c040>, ' dict ': <attribute ' dict ' of 'MyClass' objects>,
' weakref ': <attribute ' weakref ' of 'MyClass' objects>}
Class reference: <class 'type'>

(c)Explain use of import keyword with suitable example.


Importing a Module: You can import an entire module using the import statement followed
by the module name. After importing, you can access the functions, classes, and variables
defined in that module using dot notation (module_name.item_name).
import math
print(math.sqrt(25)) # Output: 5.0

Importing Specific Items from a Module: If you only need certain items from a module, you
can import them explicitly using the from ... import syntax.
from math import sqrt
print(sqrt(25)) # Output: 5.0

Importing with Alias: You can import a module with an alias to simplify its usage in your code.
import math as m
print(m.sqrt(25)) # Output: 5.0

Importing All Items from a Module: You can import all items from a module into the current
namespace using the from ... import * syntax. However, it's generally not recommended
because it can lead to namespace pollution and make your code less readable.
from math import *
print(sqrt(25)) # Output: 5.0

Conditional Import: You can conditionally import a module based on certain conditions using
the import statement inside a conditional block.
if condition:
import module_name

Importing Submodules: If a module contains submodules, you can import them using dot
notation.
import package.submodule
print(package.submodule.function())

Importing Packages: Packages are collections of modules. You can import a package and its
modules similarly to importing modules.
import package_name.module_name
print(package_name.module_name.function())
8. (a) Write a python program that shows the concept of Inheritance.
class Animal:
def init (self, name):
self.name = name
def speak(self):
pass # Abstract method, to be overridden in subclasses
class Dog(Animal): def speak(self):
return f"{self.name} says Woof!"
class
Cat(Animal):
def
speak(self):
return f"{self.name} says Meow!"
# Creating instances of
subclasses dog =
Dog("Buddy")
cat = Cat("Whiskers")
# Calling methods of base
class print("Base class
method:")
print("dog.name:", dog.name) # Output:
Buddy print("cat.name:", cat.name) #
Output: Whiskers
# Calling methods of
subclasses
print("\nSubclass
method:")
print(dog.speak()) # Output: Buddy says
Woof! print(cat.speak()) # Output:
Whiskers says Meow!

(b) Create a class Employee with data members: name, department and salary.
Create suitable methods for reading and printing employee information.
class Employee:
def init (self, name, department,
salary): self.name = name
self.department =
department self.salary =
salary
def read_employee_info(self):
self.name = input("Enter employee name: ")
self.department = input("Enter employee
department: ") self.salary = float(input("Enter
employee salary: "))
def print_employee_info(self):
print("Employee Name:",
self.name)
print("Department:",
self.department)
print("Salary:", self.salary)
# Creating an instance of the Employee class
employee1 = Employee("John Doe", "Engineering", 5000)
# Printing employee
information print("Employee
Information:")
employee1.print_employee_inf
o()
# Reading employee information employee1.read_employee_info()
# Printing updated employee information
print("\nUpdated Employee Information:")
employee1.print_employee_info()

(c) What are the differences between abstract class and interface? Write a python
program in which Maruti and Santro sub classes implement the abstract methods
of the super class Car.
1. Abstract Class:

• An abstract class can have both abstract methods (methods without implementation) and
concrete methods (methods with implementation).
• An abstract class can have instance variables.
• A class can inherit from only one abstract class.
• Abstract classes can provide a partial implementation of a class and allow subclasses to
override some methods while inheriting others.
• Abstract classes are declared using the abstract keyword.
• In Python, abstract classes are implemented using the abc module.
2. Interface:
• An interface contains only method declarations, without implementations.
• An interface cannot have instance variables.
• A class can implement multiple interfaces.
• Interfaces provide a contract that classes must adhere to, but they do not provide any
implementation.
• Interfaces are declared using normal class syntax in some languages, while in Python, they
are simulated using abstract classes with all methods declared as abstract.
• Interfaces are used to achieve abstraction and enforce polymorphism.
Now, let's see an example in Python where we have an abstract class Carwith abstract methods
start()and stop(), and two subclasses Marutiand Santro implementing these methods:

from abc import ABC, abstractmethod


class Car(ABC): # Abstract class
@abstractmethod
def start(self):
pass

@abstractmeth
od def
stop(self):
pass
class Maruti(Car): # Subclass implementing abstract methods
def start(self):
print("Maruti car started")

def stop(self):
print("Maruti car stopped")
class Santro(Car): # Subclass implementing abstract methods
def start(self):
print("Santro car started")

def stop(self):
print("Santro car stopped")
# Creating instances of
subclasses maruti = Maruti()
santro = Santro()
# Calling methods of
subclasses print("Maruti
car:") maruti.start()
maruti.stop()
print("\nSantro
car:")
santro.start()
santro.stop()

9. (a) Explain in details about namespaces and scoping.


1. Namespaces:
A namespace is a container that maps names (identifiers) to objects. It provides a way to
organize and manage the names used in a Python program.

Python implements namespaces as dictionaries where the keys are the names of objects
(variables, functions, classes) and the values are references to the objects themselves.

• Each namespace is associated with a specific scope or context in which the names are defined and
can be accessed.

• Python has several types of namespaces:

• Local Namespace: A namespace associated with a function or method. It contains names


defined within the function or method.

• Global Namespace: A namespace associated with a module. It contains names defined at the top
level of the module file.

• Built-in Namespace: A namespace containing built-in names provided by the Python interpreter.
These names are available globally in all modules.

• Namespaces allow the same name to be used for different purposes in different contexts without
causing conflicts.
2. Scoping:
a. Scoping refers to the rules that determine where and how names are looked up in a program. It
defines the visibility and accessibility of names in different parts of the code.

b. Python follows the LEGB rule to determine the order in which namespaces are searched for names:

c. Local scope: Names defined within the current function or method.


d. Enclosing (or non-local) scope: Names defined in the enclosing function(s), if any.
e. Global scope: Names defined at the top level of the module file.
f. Built-in scope: Names defined in the built-in namespace.
g. When a name is referenced in a program, Python searches for it in the local scope first, then the
enclosing scope(s), followed by the global scope, and finally the built-in scope.
h. If a name is found in multiple scopes, Python uses the name from the nearest enclosing scope.
i. The globaland nonlocal keywords can be used to modify the behavior of scoping:
j. global: Allows a variable to be assigned a value in the global scope from within a local scope.

k. nonlocal: Allows a variable to be assigned a value in an enclosing (non-local) scope from within a
nested function.
l. Scoping ensures that variables are properly encapsulated and that changes made to variables in
one part of the program do not affect variables with the same name in other parts.

(b)Explain about the import statement in modules.


Importing a Module:
• You can import an entire module by specifying its name after the import keyword. This makes all
the functions, classes, and variables defined in the module available in your current module
import module_name
Importing Specific Items from a Module:
• If you only need certain items from a module, you can import them explicitly using the from ...
importsyntax. This allows you to use those items directly without specifying the module
name.
from module_name import item1, item2, ...
Importing with Alias:
• You can import a module with an alias to simplify its usage in your code. This is particularly
useful for modules with long names or modules whose names clash with built-in names.
import module_name as alias
Importing All Items from a Module:
• You can import all items from a module into the current namespace using the from ... import *
syntax. However, it's generally not recommended because it can lead to namespace
pollution and make your code less readable.
import module_name
Conditional Import:
• You can conditionally import a module based on certain conditions using the importstatement
inside a conditional block. This allows you to import modules dynamically at runtime.

if condition:
import module_name
Importing Packages:
Packages are collections of modules. You can import a package and its modules similarly to
importing modules.
import package_name.module_name

(c)Write a function to return right most digit in the entered number.

def rightmost_digit(number):
return number % 10
# Test the function
num = int(input("Enter a number: "))
print("Rightmost digit:",
rightmost_digit(num))

10. (a) Explain the significance of xrange() function in for loop with a help of a program.

# Using range() in a for


loop print("Using
range():")
for i in range(1000000): # Create a range of 1
million numbers if i >= 10: # Print only the first
10 numbers for demonstration
break
print(i,
end=' ')

# Using xrange() in a for


loop print("\nUsing
xrange():")
for i in xrange(1000000): # Create a range of 1
million numbers if i >= 10: # Print only the first
10 numbers for demonstration
break
print(i,
end=' ')
Output:
Using range():
0123456789
Using xrange():
0 123456789

(b)Examine the program on Fibonacci series.


def fibonacci_series(n):
fib_series = [] # List to store Fibonacci series
a, b = 0, 1 # Initial values of the Fibonacci series
for _ in range(n):
fib_series.append(a)
a, b = b, a + b # Update values for the next Fibonacci number

return fib_series
# Function to print the Fibonacci
series def
print_fibonacci_series(series):
print("Fibonacci
Series:") for num in
series:
print(num, end=" ")
# Number of terms in the Fibonacci series
terms = int(input("Enter the number of terms in the Fibonacci series: "))
# Generate and print the Fibonacci
series fib_series =
fibonacci_series(terms)
print_fibonacci_series(fib_series)

1. fibonacci_series(n): This function takes the number of terms nas input and returns a list
containing the Fibonacci series up to n terms. It uses a for loop to generate the Fibonacci numbers
iteratively, starting from the initial values a = 0 and b = 1. In each iteration, it appends the current
Fibonacci number (a) to the fib_series list and updates the values of a and b for the next Fibonacci
number.
2. print_fibonacci_series(series): This function takes a list seriescontaining the Fibonacci
series as input and prints it to the console.

In the main part of the program:


• The user is prompted to enter the number of terms in the Fibonacci series.
• The fibonacci_series()function is called with the specified number of terms to generate the
Fibonacci series.
• The print_fibonacci_series()function is called to print the generated Fibonacci series.

(c)Illustrate a program to find GCD of m and n.

def gcd(m, n):


while n != 0:
m, n = n, m % n
return m

# Input the numbers


m = int(input("Enter the first number (m): "))
n = int(input("Enter the second number (n): "))

# Calculate and print the


GCD result = gcd(m, n)

print("GCD of", m, "and", n, "is:", result


11. (a) Explain Tower of Hanoi with algorithm.
The Tower of Hanoi is a classic problem in computer science and mathematics, often used to
illustrate the concept of recursion. It consists of three rods and a number of disks of different sizes,
which can slide onto any rod. The puzzle starts with the disks stacked in ascending order of size on
one rod, with the smallest disk on top, making a conical shape. The objective is to move the entire
stack to another rod, obeying the following rules:

1. Only one disk can be moved at a time.


2. Each move consists of taking the top disk from one stack and placing it on top of another stack.
3. No disk may be placed on top of a smaller disk.
Here's the algorithm to solve the Tower of Hanoi problem recursively:
1. Base Case: If there is only one disk to move, simply move it from the source rod to the destination
rod.
2. Recursive Step: If there are more than one disk, follow these steps recursively:

• Move n-1disks from the source rod to the auxiliary rod, using the destination rod as the temporary
rod.
• Move the nthdisk from the source rod to the destination rod.
• Move the n-1disks from the auxiliary rod to the destination rod, using the source rod as the
temporary rod.

Here's a Python implementation of the Tower of Hanoi algorithm:

def tower_of_hanoi(n, source, auxiliary, destination):


if n == 1:
print("Move disk 1 from rod", source, "to rod", destination)
return
tower_of_hanoi(n-1, source, destination, auxiliary)
print("Move disk", n, "from rod", source, "to rod", destination)

tower_of_hanoi(n-1, auxiliary, source, destination)


# Number of disks
n = int(input("Enter the number of disks: "))
# Calling the function to solve Tower of Hanoi
print("Steps to solve Tower of Hanoi with", n, "disks:")
tower_of_hanoi(n, 'A', 'B', 'C')

In this program:
• The tower_of_hanoi() function takes four arguments: n (the number of disks), source(the rod
from which to move the disks), auxiliary(the temporary rod to use), and destination (the rod to
which to move the disks).
• The function follows the recursive steps described above to solve the Tower of Hanoi
problem.
• The user inputs the number of disks, and the function is called with the initial parameters
to solve the problem.
(b) Write a Python program to find the factorial of the given number with and
without recursion with comparison.

# Function to find factorial without recursion


def factorial_iterative(n):
factorial = 1
for i in range(1, n + 1):
factorial *= i
return factorial

# Function to find factorial with recursion


def factorial_recursive(n):
if n == 0:
return 1
else:
return n * factorial_recursive(n - 1)

# Input the number


num = int(input("Enter a number: "))

# Calculate factorial using iterative approach


result_iterative = factorial_iterative(num)

# Calculate factorial using recursive approach


result_recursive = factorial_recursive(num)

# Print the results

print("Factorial of", num, "using iterative approach:", result_iterative)


print("Factorial of", num, "using recursive approach:", result_recursive)

# Compare the two approaches


if result_iterative == result_recursive:
print("Factorials calculated using both approaches are the same.")
else:
print("Factorials calculated using both approaches are different.")

In this program:

• factorial_iterative()is a function that calculates the factorial of a number using an iterative


approach.
• factorial_recursive()is a function that calculates the factorial of a number using a recursive
approach.
• The user inputs a number.
• The program calculates the factorial of the input number using both approaches.
• It then prints the results of both approaches.
• Finally, it compares the results and prints whether the factorials calculated using both
approaches are the same or different.
12. (a) “Tuples are immutable”. Explain with Examples.
In Python, tuples are immutable data structures, meaning that once they are created, their contents
cannot be modified. Let's explore this concept with some examples:
1. Creating a Tuple: You can craeate a tuple using parentheses (). Once created, the elements of the
tuple cannot be changed.
my_tuple = (1, 2, 3)
print(my_tuple) # Output: (1, 2, 3)
2. Accessing Elements: You can access elements of a tuple using indexing. However, you cannot
modify or reassign the values of elements.

my_tuple = (1, 2, 3)
print(my_tuple[0]) # Output: 1
# Attempting to modify a tuple will raise
an error # my_tuple[0] = 10 # This will
raise a TypeError

3. Concatenating Tuples: You can concatenate tuples to create a new tuple, but this operation does
not modify the original tuples.
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
concatenated_tuple = tuple1 + tuple2
print(concatenated_tuple) # Output: (1, 2, 3, 4, 5, 6)
4. Slicing Tuples: You can slice tuples to create new tuples containing subsets of the original elements.
Again, this operation does not modify the original tuple.
my_tuple = (1, 2, 3, 4, 5)
sliced_tuple = my_tuple[1:4]
print(sliced_tuple) # Output:
(2, 3, 4)
5. Deleting a Tuple: While you cannot modify individual elements of a tuple, you can delete the entire
tuple.
my_tuple = (1, 2, 3)
del my_tuple
# print(my_tuple) # This will raise a NameError because the tuple no longer exists
In summary, immutability in tuples means that you cannot change the elements of a tuple after it has
been created. This property makes tuples useful for representing fixed collections of items, such as
coordinates, database records, or function arguments, where you want to ensure that the data remains
unchanged throughout the program execution.

(b)Illustrate the ways of creating the tuple and the tuple assignment with suitable
programs.
1. Creating Tuples:
• Using parentheses ():
my_tuple = (1, 2, 3)

• Using the tuple() constructor:


my_tuple = tuple([1, 2, 3])

• Creating an empty tuple:


empty_tuple = ()
• Creating a tuple with a single element:
single_element_tuple = (1,) # Note the comma after the single element
2. Tuple Assignment:
• Assigning values to multiple variables from a tuple
my_tuple = (1, 2, 3)
a, b, c = my_tuple
• Swapping values of variables using tuple assignment:
a=1
b=2
a, b = b, a
• Using wildcard (*) to capture excess elements into a list:
my_tuple = (1, 2, 3, 4, 5)
first, second, *rest = my_tuple
• Ignoring elements using:
my_tuple = (1, 2, 3)
a, _, c = my_tuple

Let's put all of these together in a complete program:


# Creating tuples
tuple1 = (1, 2, 3)
tuple2 = tuple([4, 5, 6])
empty_tuple = ()
single_element_tuple = (7,)
my_tuple = (8, 9, 10)
# Tuple assignment
a, b, c = my_tuple
print("a:", a)
print("b:", b)
print("c:", c)
x = 11
y = 12
x, y = y, x # Swapping values
print("x:", x)
print("y:", y)
first, second, *rest = my_tuple
print("First:", first)
print("Second:", second)
print("Rest:", rest)
a, _, c = my_tuple # Ignoring the second element
print("a:", a)
print("c:", c)

(c)What are the accessing elements in a tuple? Explain with suitable Programs.
1. Accessing Elements by Index:
• You can access individual elements of a tuple by specifying their index position within square
brackets []. Indexing starts from 0 for the first element and increases by 1 for each subsequent
element
# Define a tuple
my_tuple = (10, 20, 30, 40, 50)

# Accessing individual elements by


index print("First element:", my_tuple[0])
# Output: 10 print("Third element:",
my_tuple[2]) # Output: 30
print("Last element:", my_tuple[-1])
# Output: 50 (negative index to access elements from the end)
2. Slicing Tuples:
• You can also extract a subset of elements from a tuple using slicing. Slicing allows you to
specify a range of indices to extract a portion of the tuple.
# Define a tuple
my_tuple = (10, 20, 30, 40, 50)

# Slicing to extract a subset of elements


subset = my_tuple[1:4] # Extract elements from index 1 to 3 (exclusive)
print("Subset:", subset) # Output: (20, 30, 40)

# Slicing with negative indices


subset = my_tuple[-3:-1] # Extract elements from the third last to the second last
print("Subset:", subset) # Output: (30, 40)

13. (a) Give example on Creating the List


# Creating an empty list
empty_list = []
print("Empty list:", empty_list)
# Creating a list with
elements my_list = [1, 2,
3, 4, 5]
print("List with elements:", my_list)
# Creating a list with elements of different
data types mixed_list = [1, "apple", True, 3.14]
print("Mixed list:", mixed_list)
# Creating a nested list (a list
of lists) nested_list = [[1, 2],
[3, 4], [5, 6]] print("Nested
list:", nested_list)
# Creating a list using the list()
constructor list_constructor =
list(range(1, 6))
print("List created using list() constructor:", list_constructor)

# Creating a list using list comprehension


list_comprehension = [x * x for x in
range(1, 6)]
print("List created using list comprehension:", list_comprehension)
Output:

Empty list: []
List with elements: [1, 2, 3, 4, 5]
Mixed list: [1, 'apple', True, 3.14]
Nested list: [[1, 2], [3, 4], [5, 6]]
List created using list() constructor: [1, 2, 3, 4, 5]
List created using list comprehension: [1, 4, 9, 16, 25]

(b)Accessing values in the Lists


1. Accessing Values by Index:
• You can access individual elements of a list by specifying their index positions within
square brackets []. Indexing starts from 0 for the first element and increases by 1 for each
subsequent element.
# Define a list
my_list = [10, 20, 30, 40, 50]

# Accessing individual elements by index


print("First element:", my_list[0]) # Output: 10
print("Third element:", my_list[2]) # Output: 30
print("Last element:", my_list[-1])
# Output: 50 (negative index to access elements from the end)
2. Slicing Lists:
• You can also extract a subset of elements from a list using slicing. Slicing allows you to
specify a range of indices to extract a portion of the list.
# Define a list
my_list = [10, 20, 30, 40, 50]

# Slicing to extract a subset of elements


subset = my_list[1:4] # Extract elements from index 1 to
3 (exclusive) print("Subset:", subset) # Output: [20, 30]

# Slicing with negative indices


subset = my_list[-3:-1] # Extract elements from the third last to the
second last print("Subset:", subset) # Output: [30, 40]

(c)Updating the Lists


1. Modifying Elements:
• You can modify individual elements of a list by directly assigning new values to specific indices.

# Define a list
my_list = [10, 20, 30, 40, 50]

# Modify an
element
my_list[2] = 35

print("Modified list:", my_list) # Output: [10, 20, 35, 40, 50]


2. Adding Elements:
• You can add new elements to the end of a list using the append()method or insert elements at
specific positions using the insert() method.

# Define a list
my_list = [10, 20, 30]
# Add an element to the end
my_list.append(40)
print("List after appending:", my_list) # Output: [10, 20, 30, 40]
# Insert an element at a specific position
my_list.insert(1, 15)
print("List after inserting:", my_list) # Output: [10, 15, 20, 30, 40]

3. Removing Elements:
• You can remove elements from a list using the remove()method to remove a specific value, or
the pop()method to remove an element by index. You can also use the delstatement to remove
an element or a slice of elements by index.
# Define a list
my_list = [10, 15, 20, 30, 40]
# Remove a specific element
my_list.remove(20)
print("List after removing element:", my_list) # Output: [10, 15, 30, 40]
# Remove an element by index
removed_element = my_list.pop(1)
print("Removed element:", removed_element)
print("List after popping element:", my_list) # Output: [10, 30, 40]

# Delete an element by index


using del del my_list[1]
print("List after deleting element:", my_list) # Output: [10, 40]

(d)Copying the list


1. Using the copy()method:
• You can use the copy()method to create a shallow copy of a list. A shallow copy creates a
new list and fills it with references to the objects found in the original list. Changes made to
the objects in the original list will be reflected in the copied list, and vice versa.
# Original list
original_list = [1, 2, 3, 4, 5]
# Creating a shallow copy
copied_list =
original_list.copy()
# Modifying the original
list original_list[0] = 10
# Printing both lists
print("Original list:", original_list) # Output: [10, 2, 3, 4, 5]
print("Copied list:", copied_list) # Output: [1, 2, 3, 4, 5
2. Using list slicing:
• You can use list slicing to create a shallow copy of a list. This method creates a new list
containing all elements from the original list. Changes made to the original list will not affect
the copied list, and vice versa.

# Original list
original_list = [1, 2, 3, 4, 5]
# Creating a shallow copy using list
slicing copied_list = original_list[:]
# Modifying the original
list original_list[0] = 10
# Printing both lists
print("Original list:", original_list) # Output: [10, 2, 3, 4, 5]
print("Copied list:", copied_list) # Output: [1, 2, 3, 4, 5]
3. Using the list()constructor:
• You can use the list() constructor to create a shallow copy of a list. This method creates a new
list containing all elements from the original list. Changes made to the original list will not
affect the copied list, and vice versa.

# Original list
original_list = [1, 2, 3, 4, 5]
# Creating a shallow copy using the list()
constructor copied_list = list(original_list)
# Modifying the original
list original_list[0] = 10
# Printing both lists
print("Original list:", original_list) # Output: [10, 2, 3, 4, 5]
print("Copied list:", copied_list) # Output: [1, 2, 3, 4, 5]

(e)Deleting the list Elements


1. Using the delstatement:
• You can use the delstatement to remove elements from a list by index or to delete the entire
list.
# Define a list
my_list = [1, 2, 3, 4, 5]
# Delete an element by index
del my_list[2]
print("List after deleting element by index:", my_list) # Output: [1, 2, 4, 5]
# Delete the entire list
del my_list
# print(my_list) # This will raise a NameError because the list no longer exists
2. Using the remove()method:
• You can use the remove()method to remove the first occurrence of a specified value from the
list.
# Define a list
my_list = [1, 2, 3, 4, 5]
# Remove a specific
element my_list.remove(3)
print("List after removing element by value:", my_list) # Output: [1, 2, 4, 5]
3. Using the pop()method:
• You can use the pop()method to remove and return an element from a specific index. If no
index is specified, it removes and returns the last element.

# Define a list
my_list = [1, 2, 3, 4, 5]
# Remove and return an element by index
removed_element = my_list.pop(2)
print("Removed element:", removed_element)
print("List after popping element by index:", my_list) # Output: [1, 2, 4, 5]
# Remove and return the last element
last_element = my_list.pop()
print("Last element:", last_element)
print("List after popping last element:", my_list) # Output: [1, 2, 4]
# Define a list
my_list = [1, 2, 3, 4, 5]
# Remove and return an element by
index removed_element =
my_list.pop(2) print("Removed
element:", removed_element)
print("List after popping element by index:", my_list) # Output: [1, 2, 4, 5]
# Remove and return the last
element last_element =
my_list.pop() print("Last
element:", last_element)
print("List after popping last element:", my_list) # Output: [1, 2, 4]

14. (a) Write a Python program to overload + operator.


class MyNumber:
def init (self, value):
self.value = value
def add (self, other):
if isinstance(other, MyNumber):
return MyNumber(self.value + other.value)
elif isinstance(other, int) or isinstance(other, float):
return MyNumber(self.value + other)
else:
raise TypeError("Unsupported operand type(s) for +: '{}' and '{}'".format(type(self),
type(other)))
def str (self):
return str(self.value)
# Create instances of MyNumber
num1 = MyNumber(10)
num2 = MyNumber(20)

# Addition using overloaded


operator result = num1 + num2
print("Result of addition:", result) # Output: Result of addition: 30

# Addition with a constant


value result = num1 + 5
print("Result of addition with constant:", result)
# Output: Result of addition with constant: 15
# Attempting to add incompatible types
try:

result = num1 + "Hello"


except TypeError as e:
print("Error:", e) # Output: Error: Unsupported operand type(s) for +: '<class
' main .MyNumber'>' and '<class 'str'>'
In this example:
• We define a class MyNumberthat represents a number.
• We overload the +operator by implementing the add ()method. Inside this method, we check
the type of the other operand and perform addition accordingly.
• If the otheroperand is another instance of MyNumber, we add their values together and return a
new MyNumber instance.
• If the otheroperand is an intor float, we add it to the value of the current instance and return a
new MyNumber instance.
• If the otheroperand is of an unsupported type, we raise a TypeError.
• We demonstrate the use of the overloaded +operator with instances of MyNumber, as well as with
constant values.
• We also demonstrate how an error is raised when attempting to add incompatible types.

(b)Differentiate Abstract class and interface with example.


1. Abstract Class:
• An abstract class in Python is a class that cannot be instantiated on its own. It typically contains
one or more abstract methods, which are methods declared but not implemented in the abstract
class. Subclasses of the abstract class must provide implementations for all the abstract methods.
• Abstract classes can also contain concrete methods, i.e., methods with
implementations.
• Abstract classes are defined using the abc module in Python.

from abc import ABC, abstractmethod


class Shape(ABC): # Abstract
class @abstractmethod
def area(self):
pass
@abstractmeth
od def perimeter(self):
pass
class Rectangle(Shape): # Concrete subclass
def init (self, length, width):
self.length = length

self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * (self.length + self.width)
rect = Rectangle(5, 4)
print("Area:", rect.area()) # Output: Area: 20
print("Perimeter:", rect.perimeter()) # Output: Perimeter: 18
2. Interface:
• In Python, interfaces are not explicitly defined as a language construct like in some other
programming languages. Instead, interfaces are usually represented using abstract classes
that contain only abstract methods (methods without implementations). Classes that
implement these methods are considered to implement the interface.
• Interfaces are more of a conceptual idea rather than a language feature, and adherence to
interfaces relies on developers following conventions.
class Animal:
def speak(self):
pass
class
Dog(Animal)
: def
speak(self):
return "Woof!"
class
Cat(Animal):
def
speak(self):
return "Meow!"
dog = Dog()
print(dog.speak()) # Output: Woof!
cat = Cat()
print(cat.speak()) # Output: Meow!
In this example:
Animalclass is an abstract class with an abstract method speak().
Dogand Catclasses are concrete subclasses of Animaland provide implementations for the
speak() method.

Although Python does not have a built-in interface construct, the Animalclass serves as
an interface, and Dog and Cat classes can be said to implement the Animal interface by
providing implementations for the speak() method.
(c)Write a python program that shows the concept of Inheritance.
# Define a
superclass class
Animal:
def init (self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclasses must implement this method")
# Define a subclass inheriting from Animal
class Dog(Animal):
def speak(self):
return "Woof!"
# Define another subclass inheriting from Animal
class Cat(Animal):
def speak(self):
return "Meow!"
# Create instances of subclasses
dog = Dog("Buddy")
cat = Cat("Whiskers")
# Access superclass attribute
print("Dog's name:", dog.name) # Output: Dog's name: Buddy
print("Cat's name:", cat.name) # Output: Cat's name: Whiskers
# Call superclass method
print("Dog says:", dog.speak()) # Output: Dog says: Woof!
print("Cat says:", cat.speak()) # Output: Cat says: Meow!
In this program:
We define a superclass Animalwith an init ()method to initialize the name attribute and a
speak() method. The speak() method raises a NotImplementedErrorsince subclasses must
provide their own implementation.
We define two subclasses Dogand Catthat inherit from the Animalsuperclass. Each subclass
provides its own implementation of the speak() method.
We create instances of the Dogand Catsubclasses, passing the names of the animals as
arguments.
We access the nameattribute of each instance to demonstrate inheritance of attributes.
We call the speak()method of each instance to demonstrate inheritance of methods, with
each subclass providing its own implementation.

15. (a) Write a python program in which Maruti and Santro sub classes implement
the abstract methods of the super class Car.
from abc import ABC, abstractmethod
# Define abstract class
Car class Car(ABC):
def init (self, model):
self.model = model
@abstractmethod
def start(self):
pass
@abstractmethod
def stop(self):
pass
# Define Maruti subclass implementing Car
class Maruti(Car):
def start(self):
return "Maruti {} started".format(self.model)
def stop(self):
return "Maruti {} stopped".format(self.model)
# Define Santro subclass implementing Car
class Santro(Car):
def start(self):
return "Santro {} started".format(self.model)
def stop(self):
return "Santro {} stopped".format(self.model)
# Create instances of Maruti and
Santro maruti_car = Maruti("Swift")
santro_car = Santro("Xing")
# Test the methods
print(maruti_car.start()) # Output: Maruti Swift started
print(maruti_car.stop()) # Output: Maruti Swift stopped
print(santro_car.start()) # Output: Santro Xing started
print(santro_car.stop()) # Output: Santro Xing stopped
In this program:
• We define an abstract class Carwith two abstract methods start()and stop().
• The Marutiand Santrosubclasses inherit from the Carsuperclass and implement their
own versions of the abstract methods.
• Instances of Marutiand Santroclasses are created with specific models.
• We test the start()and stop()methods of both subclasses to demonstrate that each subclass
provides its own implementation of these methods.

(b) Write a program to implement a student class with five-member variables and
with at least two methods to get and set values.
class Student:
def init (self):
self.name = " "
self.roll_number = " "
self.age = 0 self.grade = " "
self.department = " "

# Method to set values


def set_student_details(self, name, roll_number, age, grade, department):
self.name = name
self.roll_number = roll_number
self.age = age
self.grade = grade
self.department = department
# Method to get values
def
get_student_details(s
elf): return {
"Name": self.name,
"Roll Number": self.roll_number,
"Age": self.age,
"Grade": self.grade,
"Department": self.department
}

# Create an instance of Student


student1 = Student()
# Set values using set_student_details method
student1.set_student_details("Alice", "101", 18, "A", "Computer Science")
# Get values using get_student_details method and print
print("Student Details:")
details = student1.get_student_details()
for key, value in details.items():
print(f"{key}: {value}")

16. (a) Explain the concept of stack frame in python with an appropriate example.
In Python, a stack frame (also known as an activation record or activation frame) is a data structure
that represents a function call. Each time a function is called, a new stack frame is created to store
information such as local variables, function arguments, return address, and other execution-related
data. These stack frames are organized in a stack- like manner, where each frame corresponds to a
particular function call, with the most recent call at the top of the stack.
Let's illustrate the concept of a stack frame with an example:

def foo(x, y):


z=x+y
return z
def bar(a, b, c):
result = foo(a, b) * c
return result
# Main program
result = bar(2, 3, 4)
print("Result:", result)

(b) Create a program for linear search using function.


def linear_search(arr, target):
"""
Perform linear search to find the index of the target element in the array.
Parameters:
arr (list): The list in which to search.
target: The element to search for.
Returns:
int: The index of the target element if found, else -1.
"""
for i in range(len(arr)):
if arr[i] == target:
return i
return -1

# Example usage
arr = [10, 20, 30, 40, 50]
target = 30
index = linear_search(arr,
target) if index != -1:
print(f"Element {target} found at index {index}.")
else:
print(f"Element {target} not found in the list.")

17. (a) Write a python program to display the sum of the given series: x+1/x 2 -1/x 3
+1/x 4 ………..(-1) n /x n
def series_sum(x, n):
sum = 0
for i in range(1, n + 1):
term = ((-1) ** i) / (x ** i)
sum += term
return sum

# Input from the user


x = float(input("Enter the value of x: "))
n = int(input("Enter the value of n: "))

# Calculate the sum of the series


result = series_sum(x, n)

# Display the result


print(f"The sum of the series is: {result}")

Output:
Enter the value of x: 4
Enter the value of n: 2
The sum of the series is: -0.1875
(b) Create a program to print the following pattern
1
121
12321
1234321

def print_pattern(rows):
"""
Print the given pattern:
1
121
12321
1 234321
"""
# Loop through each row
for i in range(1, rows + 1):
# Print leading spaces
print(" " * (rows - i) * 2, end="")
# Print numbers in increasing order
for j in range(1, i + 1):
print(j, end=" ")
Output:
# Print numbers in decreasing order 1
for k in range(i - 1, 0, -1): 121
print(k, end=" ") 12321
1234321
# Move to the next line print()
# Example usage rows = 4 print_pattern(rows)

18. (a) Write a python program named Weather that is passed a dictionary of daily
temperatures, and returns the average temperature over the Weekend for the
weekly temperatures given.
def calculate_weekend_average(weekly_temperatures):
"""
Calculate the average temperature over the weekend (Saturday and Sunday) for the given
weekly temperatures.
Parameters:
weekly_temperatures (dict): A dictionary containing daily temperatures for the week.
Returns:
float: The average temperature over the weekend.
"""
weekend_temperatures = [temperature for day, temperature in weekly _ temperatures
items() if day.lower() in ['saturday', 'sunday']]
if not weekend_temperatures:
return 0 # No weekend temperatures found
return sum(weekend_temperatures) / len(weekend_temperatures)
# Example
usage weekly_temperatures = {
'Monday': 20,
'Tuesday': 22,
'Wednesday': 25,
'Thursday': 24,
'Friday': 23,
'Saturday': 28,
'Sunday': 29
}
average_weekend_temperature = calculate_weekend_average(weekly_temperatures)
print("Average temperature over the weekend:", average_weekend_temperature)
In this program:
• We define a function calculate_weekend_averagethat takes a dictionary
weekly_temperaturescontaining daily temperatures for the week as input.
• We extract the temperatures for Saturday and Sunday from the dictionary using list
comprehension and filtering by the day names.
• We calculate the average temperature over the weekend by summing up the temperatures and
dividing by the number of days in the weekend.
• If no temperatures are found for the weekend, we return 0.
• We provide an example usage of the function with a sample
weekly_temperatures dictionary.
• We print the average temperature over the weekend.

(b) Write a Python program to create a histogram from a given list of integers.
def create_histogram(numbers):
"""
Create a histogram from a given list of integers.
Parameters:
numbers (list): A list of integers.
Returns:
str: The histogram representation as a string.
"""
histogram = ""
for num in numbers:
histogram += "*" * num + "\n"
return histogram
# Example usage
numbers = [3, 7, 2, 5, 8]
histogram = create_histogram(numbers)
print("Histogram:")
print(histogram)

In this program:
We define a function create_histogramthat takes a list of integers numbersas input.
We iterate through each integer in the list and create a string of asterisks (*) representing the
histogram bar for that integer.
We concatenate these strings to form the complete histogram.
• We return the histogram string.
• We provide an example usage of the function with a sample list of integers numbers.
• We print the histogram.

19. (a) Write a python program that creates a class Student having attributes
{Enrollement_No, Name} and methods set_data that takes the values from the
user and assigns them to attributes of the class and an operator overloading
function that converts Student object to string. Also create an Class variable
student_count that will maintain the count of Student Instances and a method
that will display this count.
class Student:
# Class variable to maintain count of Student instances
student_count = 0
def init (self, enrollment_no, name):
self.enrollment_no = enrollment_no
self.name = name
# Increment student count when a new instance is created
Student.student_count += 1
def set_data(self):
"""
Method to set data (enrollment number and name) for a Student object.
"""
self.enrollment_no = input("Enter Enrollment No: ")
self.name = input("Enter Name: ")
def str (self):
"""
Operator overloading function to convert Student object to string.
"""
return f"Enrollment No: {self.enrollment_no}, Name: {self.name}"
@classmethod
def display_student_count(cls):
"""
Method to display the count of Student instances.
"""
print(f"Total number of students: {cls.student_count}")
# Example usage
student1 = Student("2021001", "Alice")
student2 = Student("2021002", "Bob")
print("Student 1:", student1)
print("Student 2:", student2)
# Set data for a student object
student3 = Student("", "")
student3.set_data()
print("Student 3:", student3)

# Display total student


count
Student.display_student_count()

(b) Create a class student with following member attributes: roll no, name, age
and total marks. Create suitable methods for reading and printing member
variables. Write a python program to overload ‘==’operator to print the details of
students having same marks.
class Student:
def init (self, roll_no, name, age, total_marks):
self.roll_no = roll_no
self.name = name
self.age = age
self.total_marks = total_marks
def read_data(self):
"""
Method to read member variables of Student.
"""
self.roll_no = input("Enter Roll No:
") self.name = input("Enter Name:
") self.age = int(input("Enter Age:
"))
self.total_marks = float(input("Enter Total Marks: "))
def display(self):
"""
Method to display member variables of Student.
"""
print(f"Roll No: {self.roll_no}")
print(f"Name: {self.name}")
print(f"Age: {self.age}")

print(f"Total Marks: {self.total_marks}")


def eq (self, other):
"""
Overloading '==' operator to compare total marks of students.
"""
return self.total_marks == other.total_marks
# Example usage
students = []
# Read data for two students
for i in range(2):
print(f"\nEnter details for Student {i+1}:")
roll_no = input("Enter Roll No: ")
name = input("Enter Name: ")
age = int(input("Enter Age: "))
total_marks = float(input("Enter Total Marks: "))
student = Student(roll_no, name, age, total_marks)
students.append(student)
# Compare total marks of students and print details of students having the same
20. (a) Write a class with following criteria Class name: Flower Objects: lilly, rose,
hibiscus Properties: price,color,smell Methods: get(), display()
class Flower:
def init (self, name, price, color, smell):
self.name = name
self.price = price
self.color = color
self.smell = smell

def get(self):
"""
Method to get properties of the flower.

"""
return {
"Name": self.name,
"Price": self.price,
"Color": self.color,
"Smell": self.smell
}
def display(self):
"""
Method to display properties of the
flower. """
print(f"Name: {self.name}")
print(f"Price: {self.price}")
print(f"Color: {self.color}")
print(f"Smell: {self.smell}")
# Create instances of Flower
lilly = Flower("Lilly", 5, "White", "Fragrant")
rose = Flower("Rose", 3, "Red", "Sweet")
hibiscus = Flower("Hibiscus", 4, "Pink", "Mild")
# Example usage
print("Details of Lilly:") lilly.display()
print("\nDetails of
Rose:") rose.display()
print("\nDetails of Hibiscus:") hibiscus.display()

(b) Write a Python program to create class GTU with attributes like class variable
cnt, instance variables x and y,instance methods get_value and print_value.
class GTU:
cnt = 0 # Class variable

def init (self, x, y):


self.x = x # Instance variable
self.y = y # Instance variable
GTU.cnt += 1 # Increment class variable cnt for each instance created
def get_value(self):
"""
Method to get the values of instance variables x and y.
"""
return self.x, self.y

def print_value(self):
"""
Method to print the values of instance variables x and y.
"""
print(f"Value of x: {self.x}")
print(f"Value of y: {self.y}")
# Example usage
gtu1 = GTU(5, 10)
gtu2 = GTU(15, 20)
# Print the number of instances created
print("Number of instances created:", GTU.cnt)
# Get and print values of instance variables for gtu1
x1, y1 = gtu1.get_value()
print("\nValues of instance variables for gtu1:")
print("x:", x1)
print("y:", y1)
# Print values of instance variables for gtu2
print("\nValues of instance variables for gtu2:")
gtu2.print_value()

You might also like