1. Introduction & Understanding Functions
Working With Functions
A function is a named, reusable block of code that performs a specific task. It helps in achieving modularity (dividing a large program into smaller parts) and reusability.
- Function Types:
- Built-in Functions: Predefined in Python (e.g.,
print(),input(),len()). - Functions defined in Modules: Available after importing a module (e.g.,
math.sqrt()). - User-defined Functions: Created by the programmer using the
defkeyword.
- Built-in Functions: Predefined in Python (e.g.,
2. Defining and Calling Functions
A function definition consists of the header and the body.
Python
def greet(name): # Function Header
"""Docstring""" # Optional description
print("Hello", name) # Function Body
greet("Alice") # Function Call/Invocation
- Parameters: Variables listed in the function definition (e.g.,
name). - Arguments: Actual values passed during the function call (e.g.,
"Alice").
3. Flow of Execution
Execution always begins at the first statement of the program. When a function call is encountered:
- The control jumps to the function definition.
- The body of the function is executed.
- Control returns to the statement immediately following the function call.
4. Passing Parameters
Python supports various ways to pass arguments:
- Positional/Required Arguments: Arguments must be provided in the correct positional order.
- Default Arguments: A parameter can have a default value used if no argument is provided (e.g.,
def calc(r, pi=3.14):). - Keyword (Named) Arguments: Arguments are matched by name, regardless of order (e.g.,
greet(name="Bob")).
5. Returning Values
Functions use the return statement to send a value back to the caller.
- Multiple Values: Python functions can return more than one value separated by commas, which are returned as a tuple.Python
def swap(a, b): return b, a
6. Scope of Variables
Scope determines the portion of the program where a variable is accessible.
- Local Scope: Variables defined inside a function. They exist only while the function is executing.
- Global Scope: Variables defined outside all functions. They are accessible throughout the program.
- LEGB Rule: Python resolves names using the Local -> Enclosed -> Global -> Built-in order.
7. Mutable/Immutable Properties
When passing data to a function:
- Immutable objects (int, string, tuple): The function receives a copy of the reference. Changes inside the function do not affect the original object (similar to “pass by value”).
- Mutable objects (list, dictionary): The function can modify the original object directly because it receives a reference to the actual data (similar to “pass by reference”).
===============================================================
Revised Study Material: Working with Functions
3.1 & 3.2 Introduction to Functions
Functions are self-contained blocks of code that perform a specific task. They prevent code duplication and make programs easier to manage.
- Built-in:
print(),len(),type() - Modules:
math.sin(),random.randint() - User-defined: Created by you using
def.
3.3 Defining Functions in Python
To define a function, use the def keyword followed by the function name and parentheses.
Example:
Python
def calculate_area(length, breadth): # Header
"""Calculates area of a rectangle""" # Docstring
area = length * breadth # Body
print("Area is:", area) # Body
calculate_area(10, 5) # Calling the function
3.4 Flow of Execution
When a program runs, Python follows the statements line by line. However, when a function is called :
- The control jumps to the function definition.
- The body of the function is executed.
- Control returns to the statement immediately following the function call.
3.5 Passing Parameters to function
There are different ways to send information (arguments) to a function:
- Positional/Required Arguments: Arguments must be provided in the correct positional order.
- Default Arguments: A parameter can have a default value used if no argument is provided (e.g.,
def calc(r, pi=3.14):). - Keyword (Named) Arguments: Arguments are matched by name, regardless of order (e.g.,
greet(name="Bob")).
3.5.1 Positional Arguments
The values are assigned to parameters based on their position.
Python
def check_grade(name, marks):
print(name, "scored", marks)
check_grade("Amit", 90) # Correct
check_grade(90, "Amit") # Logical Error: position matters
3.5.2 Default Arguments
You can assign a default value to a parameter in the header. If the caller doesn’t provide a value, the default value is used by the function.
Python
def greet(name, msg="Good Morning"):
print("Hello", name, msg)
greet("Sumit") # Uses default: Hello Sumit Good Morning
greet("Sumit", "How are you?") # Overrides default: Hello Sumit How are you?
3.5.3 Keyword (Named) Arguments
You can specify the parameter name during the call to ignore the position/order of the parameters.
def interest(principal, rate, time):
return (principal * rate * time) / 100
# Order doesn't matter if names are used
print(interest(rate=8, time=2, principal=1000))
3.6 Returning Values
A function can send a result back to the main program using the return statement.
def get_stats(numbers):
high = max(numbers)
return high
max_val = get_stats([10, 20, 30])
print(max_val)
Returning Multiple Values:
Python can also return multiple values as a tuple.
def get_stats(numbers):
high = max(numbers)
low = min(numbers)
return high, low # Returns a tuple (high, low)
max_val, min_val = get_stats([10, 20, 30])
3.8 Scope of Variables
Scope defines where a variable can be “seen” or used. Scope determines the portion of the program where a variable is accessible.
- Local Scope: Variables defined inside a function. They exist only while the function is executing.
- Global Scope: Variables defined outside all functions. They are accessible throughout the program.
x = 10 # Global
def my_func():
y = 5 # Local
print(x) # Accessible
print(y) # Accessible
my_func()
# print(y) # Error: y is not defined outside the function
LEGB Rule:
Python resolves names using the following order:
Local -> Enclosed -> Global -> Built-in
The LEGB rule in Python explains how variable names are resolved (searched) when you use them in code.
LEGB stands for:
- L — Local
- E — Enclosing
- G — Global
- B — Built-in
Python searches for variables in this order.
1. Local Scope (L)
Variables defined inside a function.
def my_func():
x = 10 # local variable
print(x)
my_func()
Output:
10
Here, x exists only inside my_func().
2. Enclosing Scope (E)
Variables in an outer function enclosing an inner function.
def outer():
x = 20 # enclosing variable
def inner():
print(x)
inner()
outer()
Output:
20
inner() cannot find x locally, so it checks the enclosing function outer().
3. Global Scope (G)
Variables defined outside all functions.
x = 30 # global variable
def my_func():
print(x)
my_func()
Output:
30
Python checks global scope if not found locally or enclosing.
4. Built-in Scope (B)
Python’s predefined names/functions like print(), len(), sum().
numbers = [1, 2, 3]
print(len(numbers))
Output:
3
len is found in Python’s built-in scope.
Full LEGB Example
x = "Global"
def outer():
x = "Enclosing"
def inner():
x = "Local"
print(x)
inner()
outer()
Output:
Local
Python finds x in Local scope first.
Another Example Showing Search Order
x = "Global"
def outer():
x = "Enclosing"
def inner():
print(x)
inner()
outer()
Output:
Enclosing
Search order:
- Local → not found
- Enclosing → found
So Python prints "Enclosing".
Important Note: global and nonlocal
Using global
If you want to modify a global variable inside a function, you must use the global keyword.
x = 5
def change():
global x
x = 100
change()
print(x)
Output:
100
Using nonlocal
def outer():
x = 10
def inner():
nonlocal x
x = 50
inner()
print(x)
outer()
Output:
50
LEGB Search Flow
When Python sees a variable:
Local → Enclosing → Global → Built-in
The first match found is used.
3.9 Mutable/Immutable Properties of Arguments
This is a critical concept for exams. It dictates whether a function can change the original variable passed to it.
- Immutable (Integers, Strings, Tuples): Changes inside the function do not reflect in the original variable.
- Mutable (Lists, Dictionaries): Changes inside the function do reflect in the original variable.
Example with a List (Mutable):
def modify_list(lst):
lst.append(100) # Changes the original list
print("Inside function:", lst)
my_list = [1, 2, 3]
modify_list(my_list)
print("Outside function:", my_list) # Output: [1, 2, 3, 100]
=================================================——
2. Mutable vs. Immutable Properties
This concept determines if the “original” data changes when passed as an argument.
A. Immutable Objects (Integers, Strings, Tuples)
When you pass an immutable object, the function creates a local copy. The original remains unchanged.
Python
def increment(n):
n += 1
print("Value inside function:", n)
val = 10
increment(val)
print("Value outside function:", val)
Output:
Value inside function: 11
Value outside function: 10
B. Mutable Objects (Lists, Dictionaries)
When you pass a list or dictionary, the function receives a reference to the actual memory location. Any changes made inside the function affect the original object.
Python
def add_item(my_list):
my_list.append("New Item")
print("List inside:", my_list)
fruits = ["Apple", "Banana"]
add_item(fruits)
print("List outside:", fruits)
Output:
List inside: [‘Apple’, ‘Banana’, ‘New Item’]
List outside: [‘Apple’, ‘Banana’, ‘New Item’]
Comparison Table for Quick Revision
| Feature | Local Scope | Global Scope |
| Defined | Inside a function | Outside all functions |
| Lifetime | Deleted when function ends | Exists until program ends |
| Accessibility | Only inside that function | Accessible everywhere |
| Data Type | Property | Effect of Function Modification |
| Int, String, Tuple | Immutable | Original value never changes |
| List, Dictionary | Mutable | Original value does change |
===============================================================
Questions for Practice
Section A: Variable Scope (LEGB Rule)
Question 1
What will be the output of the following Python code?
Python
val = 20
def display():
val = 10
print(val, end=" ")
display()
print(val)
- Concepts tested: Local vs. Global scope.
Question 2
Identify the error in the following code snippet and suggest the correction:
Python
count = 0
def increment():
count = count + 1
print(count)
increment()
- Concepts tested: Modifying a global variable inside a local scope.
Question 3
What will be the output of the following code?
Python
def outer():
x = "local"
def inner():
nonlocal x
x = "nonlocal"
print("inner:", x)
inner()
print("outer:", x)
outer()
- Concepts tested: Nested functions and the
nonlocalkeyword.
Section B: Mutable vs. Immutable Properties
Question 4
Predict the output of the following code:
Python
def process(a):
a = a + [10]
print("Inside:", a)
my_list = [1, 2, 3]
process(my_list)
print("Outside:", my_list)
- Concepts tested: Behavior of lists during reassignment (concatenation) versus in-place modification.
Question 5
What will the following code print?
Python
def change_data(data):
data[1] = 99
data = [4, 5, 6]
numbers = [1, 2, 3]
change_data(numbers)
print(numbers)
- Concepts tested: Mutable object modification via indexing vs. variable reassignment.
Question 6
Consider the following function. What is the output?
Python
def update_str(s):
s = s + " World"
return s
msg = "Hello"
update_str(msg)
print(msg)
- Concepts tested: Immutability of strings.
Section C: Mixed Concepts (Advanced)
Question 7
Trace the output of this code carefully:
Python
def func(p, q=10):
p = p + q
q = p - q
print(p, "#", q)
return p
r = 5
r = func(r)
print(r)
- Concepts tested: Default arguments, arithmetic updates, and return values.
Question 8
Analyze the following code and write the output:
Python
def my_func(a):
a.append(a[0])
a[0] = 5
v = [1, 2]
my_func(v)
print(v)
- Concepts tested: List methods and in-place mutation.
Question 9:
Identify the valid/invalid function call statement(s)
def add(n1,n2,n3=5):
return n1+n2+n3
result1=add(6,7,8)
result2=add(5)
result3=add(4,8,n1=5)
result4=add(2,9, n3=88)
result5=add(n2=6,n1=7)
result6=add(n1=10, 5, 6)
In Python, function calls must follow specific rules regarding positional arguments (values passed in order) and keyword arguments (values assigned to specific names).
Answer:
| Statement | Status | Reason |
result1=add(6,7,8) | Valid | Passes three positional arguments. n1=6, n2=7, and n3 is overridden from 5 to 8. |
result2=add(5) | Invalid | Missing argument. The function requires at least two arguments (n1 and n2). Only n3 has a default value. |
result3=add(4,8,n1=5) | Invalid | Multiple values for ‘n1’. The first positional argument 4 is already assigned to n1. You cannot assign to it again via keyword. |
result4=add(2,9, n3=88) | Valid | Correct use of positional arguments for n1 and n2, and a keyword argument to override n3. |
result5=add(n2=6,n1=7) | Valid | Correct use of keyword arguments. Since they are named, the order doesn’t matter. n3 will use its default value of 5. |
result6=add(n1=10, 5, 6) | Invalid | Syntax Error. Positional arguments (5, 6) cannot follow keyword arguments (n1=10). All positional arguments must come first. |
Summary of Key Rules
- Required vs. Optional: Arguments without default values (like
n1andn2) are mandatory. - The Order Rule: Once you use a keyword argument (e.g.,
name=value), you cannot go back to using plain positional arguments in that same call. - No Double Dipping: You cannot provide a value for the same parameter more than once.
Question 10:
You have a function defined as follows:
def calc_vol(length, width, height=10, scale=1):
return (length * width * height) * scale
Identify which of the following calls are Valid or Invalid and state the reason why.
A) calc_vol(2, 3)
B) calc_vol(width=5, length=2)
C) calc_vol(2, width=3, 5)
D) calc_vol(length=2, 3, height=5)
E) calc_vol(2, 3, height=5, 2)
F) calc_vol(4, 5, length=2)
G) calc_vol(2, 4, scale=0.5)
H) calc_vol(width=10)
I) calc_vol(1, 2, 3, 4)
Answer:
| Call Statement | Status | Reason |
A) calc_vol(2, 3) | Valid | length=2, width=3. Uses defaults for height (10) and scale (1). |
B) calc_vol(width=5, length=2) | Valid | Keyword arguments can be provided in any order. |
C) calc_vol(2, width=3, 5) | Invalid | Syntax Error: Positional arguments cannot follow keyword arguments. |
D) calc_vol(length=2, 3, height=5) | Invalid | Syntax Error: Again, the positional 3 appears after a keyword argument. |
E) calc_vol(2, 3, height=5, 2) | Invalid | Syntax Error: A positional argument (2) follows a keyword argument (height=5). |
F) calc_vol(4, 5, length=2) | Invalid | Multiple Values: 4 is assigned to length positionally, but length=2 tries to assign to it again. |
G) calc_vol(2, 4, scale=0.5) | Valid | Skips the default height and provides a specific scale. |
H) calc_vol(width=10) | Invalid | Missing Argument: length is a required positional/keyword argument and was not provided. |
I) calc_vol(1, 2, 3, 4) | Valid | Overwrites all defaults using positional ordering. |