Unit 5: Functions & Strings — Theory Questions (5 Marks Each)
Q1) Explain the concept of a function in Python. How do function definition
and function call work? Illustrate with a simple example.
Concept of a Function in Python
What is a Function?
A function in Python is a block of reusable code that performs a specific task.
Functions help in:
• Reducing code repetition
• Improving readability
• Making programs easier to test and maintain
Python provides built-in functions (like print(), len()) and also allows users to create user-
defined functions.
Function Definition
A function is defined using the def keyword, followed by:
1. Function name
2. Parentheses () (may contain parameters)
3. Colon :
4. Indented function body
Syntax:
def function_name(parameters):
# function body
return value # optional
Function Call
A function call means executing the function.
It is done by writing the function name followed by parentheses, passing arguments if
required.
Syntax:
function_name(arguments)
Simple Example
Function Definition:
def add(a, b):
result = a + b
return result
Function Call:
sum_value = add(10, 5)
print(sum_value)
Output:
15
Explanation of the Example
• def add(a, b): → defines a function named add with two parameters.
• result = a + b → performs addition.
• return result → sends the result back to the caller.
• add(10, 5) → calls the function with arguments 10 and 5.
Summary
Term Description
Function Reusable block of code
Function Definition Creating a function using def
Function Call Executing the function
Parameters Variables in function definition
Arguments Values passed during function call
Conclusion
Functions allow code reuse, better organization, and clarity.
In Python, functions are defined using def and executed through function calls with required
arguments.
Q2) What is recursion? Write a recursive function in Python to find the factorial
of a number.
What is Recursion?
Recursion is a programming technique in which a function calls itself to solve a problem by
breaking it into smaller sub-problems.
A recursive solution must have:
1. Base case – a condition that stops the recursion
2. Recursive case – the part where the function calls itself
Without a base case, recursion would continue infinitely.
Recursive Function to Find Factorial
Mathematical Definition
𝑛! = 𝑛 × (𝑛 − 1)! and0! = 1
Python Program (Recursive)
def factorial(n):
# Base case
if n == 0 or n == 1:
return 1
# Recursive case
else:
return n * factorial(n - 1)
Function Call
result = factorial(5)
print(result)
Output:
120
How the Recursion Works (for n = 5)
factorial(5)
= 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 * factorial(1)
=5*4*3*2*1
= 120
Key Points
Term Meaning
Recursion Function calling itself
Base Case Stops recursion
Recursive Case Function calls itself
Advantage Simple and elegant solution
Disadvantage More memory due to function calls
Conclusion
Recursion is useful for problems that can be divided into smaller similar problems, such as
factorial, Fibonacci series, and tree traversal. The base case is essential to avoid infinite
recursion.
Q3) Discuss optional arguments and default parameters in Python functions,
with examples.
Optional Arguments and Default Parameters in Python Functions
In Python, optional arguments are implemented using default parameters.
A parameter becomes optional when it is given a default value in the function definition.
If the caller does not provide a value, the default value is used automatically.
1. Default Parameters
Concept
A default parameter is a parameter that has a predefined value in the function definition.
Syntax
def function_name(parameter=value):
statement
Example: Function with Default Parameter
def greet(name, message="Good Morning"):
print(message, name)
Function Calls
greet("Amit")
greet("Neha", "Welcome")
Output:
Good Morning Amit
Welcome Neha
message is optional because it has a default value.
2. Optional Arguments
Concept
• Arguments that may or may not be passed during a function call.
• If not passed, their default value is used.
Example: Optional Argument
def power(base, exponent=2):
return base ** exponent
Function Calls
print(power(5))
print(power(5, 3))
Output:
25
125
Here, exponent is optional.
3. Rules for Default Parameters
Rule 1: Default Parameters Must Come Last
def test(a, b=10): # Correct
pass
Incorrect:
def test(a=10, b):
pass
Rule 2: Default Values Are Evaluated Once
(Important concept)
def add_item(item, lst=[]):
[Link](item)
return lst
print(add_item(1))
print(add_item(2))
Output:
[1]
[1, 2]
Same list is reused.
Correct approach:
def add_item(item, lst=None):
if lst is None:
lst = []
[Link](item)
return lst
Summary Table
Feature Description
Default Parameter Parameter with predefined value
Optional Argument Argument that may be omitted
Benefit Flexible and cleaner function calls
Rule Default parameters must be at the end
Conclusion
Default parameters make function arguments optional, improving flexibility and readability.
Proper ordering and careful use with mutable objects are important to avoid unexpected
behavior.
Q4) Explain immutability in Python strings. How do string functions and
methods demonstrate this property?
Immutability in Python Strings
What is Immutability?
Immutability means that an object’s value cannot be changed after it is created.
In Python, strings are immutable, so once a string is created, its characters cannot be
modified.
1. Immutability in Python Strings
Example: Direct Modification Not Allowed
text = "Python"
text[0] = "J"
Output:
TypeError: 'str' object does not support item assignment
This shows that string characters cannot be changed.
2. How String Methods Demonstrate Immutability
String methods do not change the original string.
Instead, they return a new string with the required modification.
Example 1: upper() Method
name = "python"
new_name = [Link]()
print(name)
print(new_name)
Output:
python
PYTHON
Original string remains unchanged.
Example 2: replace() Method
text = "I like Java"
new_text = [Link]("Java", "Python")
print(text)
print(new_text)
Output:
I like Java
I like Python
Example 3: strip() Method
msg = " Hello "
print([Link]())
print(msg)
Output:
Hello
Hello
3. String Operations Also Show Immutability
Concatenation Creates a New String
a = "Hello"
b = a + " World"
print(a)
print(b)
Output:
Hello
Hello World
4. Why Strings Are Immutable
• Improves memory efficiency (string interning)
• Makes strings thread-safe
• Prevents accidental modification of data
Summary Table
Operation Effect
Character assignment Not allowed
String methods Return new strings
Operation Effect
Original string Remains unchanged
Conclusion
Immutability in Python strings ensures safety and efficiency.
All string functions and methods demonstrate this by returning new strings instead of
modifying existing ones, clearly proving the immutable nature of strings.
Q5) Describe at least three built-in string methods in Python and provide sample
usages.
Built-in String Methods in Python (with Examples)
Python provides many built-in string methods to perform common operations on strings.
Since strings are immutable, all these methods return a new string without changing the
original one.
Below are three commonly used string methods with sample usages.
1. upper() Method
Purpose:
Converts all characters in a string to uppercase.
Example:
text = "python programming"
result = [Link]()
print(result)
Output:
PYTHON PROGRAMMING
2. lower() Method
Purpose:
Converts all characters in a string to lowercase.
Example:
text = "HELLO WORLD"
result = [Link]()
print(result)
Output:
hello world
3. replace() Method
Purpose:
Replaces a substring with another substring and returns a new string.
Syntax:
[Link](old, new)
Example:
sentence = "I like Java"
new_sentence = [Link]("Java", "Python")
print(new_sentence)
Output:
I like Python
Additional Common String Methods (Optional)
strip()
Removes leading and trailing spaces.
msg = " Hello "
print([Link]())
find()
Finds the position of a substring.
text = "Python"
print([Link]("t"))
Summary Table
Method Description
upper() Converts string to uppercase
lower() Converts string to lowercase
replace() Replaces part of a string
strip() Removes extra spaces
find() Finds position of substring
Conclusion
Built-in string methods in Python make text processing simple and efficient.
They always return new strings, reinforcing the immutable nature of Python strings.
Q6) How is a string sliced in Python? Write an example to show slicing
operations.
String Slicing in Python
What is String Slicing?
String slicing is the process of extracting a portion (substring) from a string using index
positions.
Since strings are immutable, slicing creates and returns a new string without modifying the
original one.
Syntax of String Slicing
string[start : end : step]
• start → starting index (inclusive)
• end → ending index (exclusive)
• step → interval between characters (optional)
Example String
text = "PYTHONPROGRAMMING"
Index positions:
P Y T H O N P R O G R A M M I N G
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Examples of String Slicing
1. Basic Slicing
print(text[0:6])
Output:
PYTHON
2. Slicing Without Start Index
print(text[:6])
Output:
PYTHON
3. Slicing Without End Index
print(text[6:])
Output:
PROGRAMMING
4. Slicing Using Step
print(text[::2])
Output:
PTOPOGAMN
5. Slicing with Negative Indices
print(text[-11:-1])
Output:
PROGRAMMIN
6. Reverse a String Using Slicing
print(text[::-1])
Output:
GNIMMARGORPNOHTYP
Summary
Feature Description
Purpose Extract substring
Indexing Positive & negative
Step Optional
Original string Unchanged
Conclusion
String slicing in Python is a powerful and flexible way to extract substrings using indices and
steps, while maintaining the immutable nature of strings.
Q7) Define passing functions as arguments in Python. Why is it useful? Give an
example scenario.
Passing Functions as Arguments in Python
Definition
In Python, functions are first-class objects, which means:
• Functions can be assigned to variables
• Functions can be passed as arguments to other functions
• Functions can be returned from other functions
Passing a function as an argument means giving a function reference to another function so
it can be called inside that function.
Why Is It Useful?
Passing functions as arguments is useful because it:
1. Increases code reusability
2. Enables flexible and customizable behavior
3. Supports functional programming concepts
4. Avoids code duplication
5. Makes programs more modular and clean
Basic Example
def add(a, b):
return a + b
def operate(func, x, y):
return func(x, y)
result = operate(add, 5, 3)
print(result)
Output:
Here, the function add is passed as an argument to operate.
Example Scenario (Real-World Use Case)
Scenario: Applying Different Operations on Data
def square(n):
return n * n
def cube(n):
return n * n * n
def apply_operation(operation, value):
return operation(value)
print(apply_operation(square, 4))
print(apply_operation(cube, 4))
Output:
16
64
The same function apply_operation() works differently based on the function passed.
Common Built-in Example
Using sorted() with a Function
words = ["banana", "apple", "cherry"]
result = sorted(words, key=len)
print(result)
Output:
['apple', 'banana', 'cherry']
The function len is passed as an argument.
Summary Table
Feature Description
Concept Functions passed as arguments
Benefit Flexible and reusable code
Example Uses map(), filter(), sorted()
Programming Style Functional programming
Conclusion
Passing functions as arguments allows Python programs to be more flexible, reusable, and
modular. It is widely used in callbacks, sorting, data processing, and functional
programming.
Q8) Describe the linear search algorithm and write a Python function prototype
for it.
Linear Search Algorithm
Description
Linear search (also called sequential search) is a simple searching algorithm used to find a
target element in a list or array.
• The algorithm checks each element one by one from the beginning of the list.
• It compares every element with the key (target value).
• If a match is found, the search stops immediately.
• If the end of the list is reached and the element is not found, the search fails.
Linear search works on both sorted and unsorted data.
Steps of Linear Search
1. Start from the first element of the list.
2. Compare the current element with the key.
3. If they are equal, return the index/position.
4. If not, move to the next element.
5. Repeat until the element is found or the list ends.
Time Complexity
• Best case: 𝑂(1)(element found at first position)
• Worst case: 𝑂(𝑛)(element at last position or not present)
• Average case: 𝑂(𝑛)
Python Function Prototype for Linear Search
A function prototype shows the function name, parameters, and return type (conceptually).
Prototype
def linear_search(arr, key):
pass
Example Implementation (for clarity)
def linear_search(arr, key):
for index in range(len(arr)):
if arr[index] == key:
return index
return -1
Example Usage
numbers = [10, 25, 30, 45, 50]
result = linear_search(numbers, 30)
print(result)
Output:
Conclusion
Linear search is easy to understand and implement. It is suitable for small datasets or
unsorted lists, but inefficient for large datasets due to its 𝑂(𝑛)time complexity.