Python Functions

Functions are fundamental building blocks in Python that allow you to organize your code, promote code reusability, and improve readability. They are essentially named blocks of code that perform specific tasks.

Defining a function


def function_name(parameters):
  # Function body
  # Statements to be executed
  return value  # Optional

def : Keyword that declares the start of a function definition.

function_name : User-defined name that identifies the function.

parameters (optional) : A comma-separated list of variables that accept values when the function is called. These are used to pass data to the function.

Function body : The indented block of code that contains the statements or instructions to be executed when the function is called.

return : A statement that outputs a value from the function. The function execution stops after a return statement is encountered.

Calling a function


function_name(arguments)

function_name : The same name used when defining the function.

arguments : A comma-separated list of values that are passed to the function's parameters during the call. The number and order of arguments should match the parameters defined in the function.

Example


def greet(name):
  print("Hello,", name + "!")
# Calling the greet function
greet("Sunil")  
# Output: Hello, Sunil!

Function Arguments in Python

Function arguments are the values you pass to a function when you call it. They act as a way to provide the function with specific data it needs to perform its task.

1. Required Arguments:

These are the most basic type of arguments. They are defined in the function definition without any default values. When you call the function, you must provide values for all required arguments in the correct order.


def greet(name):
    print("Hello,", name + "!")

greet("Sunil")  # Output: Hello, Sunil!

2. Default Arguments:

Default arguments are optional arguments that come with a pre-defined value in the function definition. If you don't provide a value for a default argument during the function call, the default value is used instead.


def calculate_area(length, width=10):  
    area = length * width
    return area

area1 = calculate_area(5, 4) 
print(area1)  # output 20
area2 = calculate_area(7)  
print(area2) # output 70

3. Keyword Arguments:

Keyword arguments allow you to pass arguments to a function by name. This is useful when you have many arguments or want to call the function with arguments in a different order than defined.


def full_name(first_name, last_name):
    return first_name + " " + last_name

# Calling by position
name1 = full_name("Sunil", "Kumar")  
print(name1) # name1 will be "Sunil Kumar"

# Calling by keyword (order doesn't matter)
name2 = full_name(last_name="Singh", first_name="Jalil") 
print(name2) # name2 will be "Jalil Singh"

4. Arbitrary positional arguments:

These are captured using an asterisk (*) before a parameter name. Any arguments passed to the function after this parameter will be collected as a tuple within the function.


def greet_all(*names):
    for name in names:
        print("Hello,", name)

greet_all("Sunil", "Anil", "Jalil") 
greet_all("amit","sumit");

5. Arbitrary keyword arguments:

These are captured using two asterisks (**) before a parameter name. Any keyword arguments passed to the function will be collected as a dictionary within the function.


def user_info(name, age, **info):
    print("Name:", name)
    print("Age:", age)
    for key, value in info.items():
        print(key, ":", value)

user_info("Sunil", 30, city="New Delhi", occupation="Python Programmer")
user_info("Amit",28, address="H. 2020",city="Gurgaon" )

6. Positional-Only Arguments:

These are parameters that can only be passed to a function by position (their order in the function call). You cannot use keyword arguments (name=value) to specify them.


def my_function(x, /):
  print(x)

my_function(10)

# example 2
def greet(name, /, message="Hi"):
    print(message + ",", name + "!")

greet("Sunil")  # Output: Hi, Sunil!
# greet(message="Hello", name="Sunil")  # error
greet("Sunil", "Hello")  

7. Keyword-Only Arguments:

Keyword-only arguments are parameters that can only be passed to a function using keyword arguments (name=value). You cannot specify them by position in the function call.


def my_function(*, x):
  print(x)

my_function(x = 10)

# example 2
def configure(name, *, age=None, location="Unknown"):
    print("Name:", name)
    if age:
        print("Age:", age)
    print("Location:", location)

configure("Sunil", age=30) 
# configure("Amit", 25)  # error
configure("Sumit", location="New Delhi")  

Call by value and Call by reference

In Python, unlike some other programming languages, function argument passing doesn't strictly fall into call by value or call by reference.

Python utilizes a concept called "call by object reference" or "call by assignment." This means when you pass an argument to a function, you're essentially passing a reference or pointer (memory location) to the object's value, not the value itself.

The behavior of this reference passing depends on the mutability of the object being passed:

Immutable Objects (Call by Value Behavior):

Immutable objects in Python are those that cannot be changed after creation (e.g., integers, strings, tuples).


def modify_number(num):
    num = num + 10  

number = 5
modify_number(number)
print(number)  # Output: 5 
 

Mutable Objects (Call by Reference Behavior):

Mutable objects in Python are those that can be modified after creation (e.g., lists, dictionaries, sets).


def modify_list(my_list):
    my_list.append(100)  

my_list = [1, 2, 3]
modify_list(my_list)
print(my_list)  # Output: [1, 2, 3, 100] 

 

Return values

return statement is used in function to return value from function.


def my_function(n):
    return n*5;

output = my_function(10)
print(output)

Types of functions

There are 4 types of functions in python.

1. Built-in Functions:

These functions come pre-installed with Python and can be used directly without any need for definition.


# Find the length of a string
my_string = "Hello, world!"
string_length = len(my_string)
print(string_length)  # Output: 13

# Calculate the minimum value in a list
numbers = [5, 2, 8, 1]
minimum_value = min(numbers)
print(minimum_value)  # Output: 1

2. User-defined Functions:

You define these functions yourself to perform specific tasks within your program.


def greet(name):
  print("Hello,", name + "!")
greet("Sunil")  

3. Lambda Functions:

These are anonymous functions defined in a single line, useful for short expressions.

A lambda function can take any number of arguments, but can only have one expression.


# Calculate the area of a square using a lambda function
area = lambda side: side * side

square_side = 5
square_area = area(square_side)
print(square_area)  # Output: 25

# Multiply argument 
x = lambda a, b : a * b
print(x(5, 6))

# print all even number from given list
numbers = [1, 2, 3, 4, 5]
even_numbers = list(filter(lambda num: num % 2 == 0, numbers))
print(even_numbers)  # Output: [2, 4]
 

Here's a comparison between a regular function and a lambda function for adding two numbers:


# Regular function
def add(x, y):
  return x + y

# Lambda function
add_lambda = lambda x, y: x + y

# Calling both functions
result1 = add(5, 3)
result2 = add_lambda(5, 3)

print(result1, result2)  # Output: 8 8

 

You can use lambda functions as key functions for sorting to define custom sorting criteria.


fruits = ['apple', 'banana', 'cherry']
fruits.sort(key=lambda fruit: fruit.lower())  
# Sorts fruits case-insensitively 

Using lambda function, a anonymous function inside another function


def myfunc(n):
    return lambda a: a * n
  
doubler = myfunc(2)  # Create a function that doubles numbers (n=2)
tripler = myfunc(3)  # Create a function that triples numbers (n=3)

result1 = doubler(5)  # result1 will be 10 (5 * 2)
result2 = tripler(7)  # result2 will be 21 (7 * 3)
print(result1)
print(result2)

4. Recursive Functions:

These functions call themselves within their definition to solve problems with a self-similar structure.


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

result = factorial(5)
print(result)  # Output: 120

Python Functions Exercies

1. Define a function called greet that prints "Hello, World!" when called.

2. Write a function called square that takes a number as input and returns its square.

3. Explain the difference between parameters and arguments in a function.

4. Write a function called add that takes two numbers as parameters and returns their sum.

5. Explain the concept of default parameters in Python functions with an example.

6. Write a function called print_info that takes a person's name, age, and city as parameters, with age having a default value of 25.

7. Define a function called calculate_sum that takes any number of arguments and returns their sum.

8. Explain the use of *args and **kwargs in Python functions.

9. Write a function called average that calculates the average of a variable number of numbers passed as arguments.

10. Write a recursive function to calculate the factorial of a given number.

11. Discuss the advantages and disadvantages of using recursion in Python functions.

12. Implement a recursive function called fibonacci to generate the nth Fibonacci number.

13. Explain the concepts of local and global scope in Python functions.

14. Write a function called increment that increments a global variable counter by 1.

15. Discuss the lifetime of variables defined inside a function.

16. Define a lambda function to calculate the square of a number.

17. Explain the differences between lambda functions and regular functions in Python.

18. Write a function that takes a list of numbers and returns a new list with each element squared using lambda functions.

19. Define a function called apply_function that takes a function and a list as arguments, and applies the function to each element of the list.

20. Discuss the concept of higher-order functions in Python with examples.

21. Write a function called modify_list that takes a list and a modification function as arguments, and modifies the list according to the modification function.

22. Compare and contrast recursion and iteration in Python functions.

23. Write an iterative function to calculate the factorial of a given number.

24. Explain the purpose of using try-except blocks in Python functions.

25. Write a function called safe_divide that takes two numbers as arguments and handles the ZeroDivisionError exception.

26. Define a function decorator called timer that calculates and prints the time taken by a function to execute.

27. Explain the concept of function decorators in Python and their applications.

28. Write a function that is decorated with the timer decorator to measure its execution time.