Master Python Functions: Rules for Clean, Reusable Code(2025)

Table of Contents

What is a Function in Python?

A function is a reusable block of code that performs a specific task. You define it once and use it whenever you need it.

Consider an example below.

				
					def greet():
    print("Hello, welcome to Python!")
greet()

#   Hello, welcome to Python!

				
			

Anatomy of a Python Function

A function can be created by using the def keyword. A function name can contain letters, numbers and underscores but it cannot start with a number. Finally to call a function write its name outside the function followed by parentheses. A return statement can be used to return the data back to the code that is calling it.

Every Python function follows this structure:

def function_name(parameters):
        # Function body
return value

 

Consider the example below to add two numbers

				
					def add_numbers(a, b):
    return a + b
result = add_numbers(5, 10)
print(result)

#   15
				
			

Analysis:

We define a function called as add_numbers with variables a and b.

The function returns the addition of a and b.

Outside the function it is called by declaring a variable called result and finally prints the result.

 

Types of Python Functions

 

Built-in Functions

These are the Python built-in functions.

print(), len(), type(), max(), min(), sum()

 

User-defined Functions

These are the functions created by the users by using the def keyword.

Lambda (Anonymous) Functions

They’re used for small, one-line operations.

square = lambda x: x * x

print(square(4))  # Output: 16

 

Parameters and Arguments Explained

Functions can take inputs (called parameters) and receive values (called arguments).

				
					def introduce(name, age):
    print(f'My name is {name} and I’m {age} years old.') 

introduce("Rakshath", 20)
# Output: My name is Rakshath and I’m 20 years old.

				
			

In the above code name and age are the parameters and “Sunny” and 20 are arguments.

 

Default and Keyword Arguments

 

A parameter that has a predefined value is called a default argument. If you don’t pass a value for it Python uses the default.

Why use default arguments?

  • To make parameters optional
  • to provide fallback values
  • to reduce errors when arguments are missing

 

Keyword Arguments

In keyword arguments, you specify the parameter name when calling the function.
This makes the function call more clear and order-independent.

Why use keyword arguments?

  • Increases readability

  • You can pass arguments in any order

  • Useful when functions have many parameters

  • Helps avoid mistakes

				
					# Default Arguments
def greet(name="Guest"):
    print("Hello,", name)

# Keyword Arguments
def student_info(name, age):
    print("Name:", name)
    print("Age:", age)
    
# Demonstrate Default Arguments
greet()                                 #  Hello, Guest
greet("Farnaz")                         #  Hello, Farnaz

# Demonstrate Keyword Arguments (Order doesn't matter)
student_info(age=20, name="Shin Chan")  # Name: Shin Chan
                                        # Age: 20
# Using positional arguments (Order matters)
student_info("Farnaz", 20)              # Name: Farnaz
                                        # Age: 20
				
			

Sometimes you don’t know how many arguments you will pass and that’s where the  *args and **kwargs come to play. Both of them can take unknown number of arguments.

 

Arbitrary Arguments   *args

 

The *args can take a tuple of all the passed elements and allow you to accept any number of positional arguments.

				
					def describe_flavors(*flavors):
    print("Type of collected arguments:", type(flavors))
    
    print(f"Number of flavors: {len(flavors)}") 
    print(f"The first flavor listed is: {flavors[0]}")
    print("Listing all flavors:")
    
    for flavor in flavors:
        print(f"- {flavor}")

describe_flavors("Vanilla", "Chocolate", "Strawberry", "Mint")

#    Type of collected arguments: <class 'tuple'>
#    Number of flavors: 4
#    The first flavor listed is: Vanilla
#    Listing all flavors:
#    - Vanilla
#    - Chocolate
#    - Strawberry
#    - Mint
				
			

Arbitrary Keyword Arguments- **kwargs

 

The **kwargs syntax enables a function to gather an indefinite number of keyword arguments.

When you use **kwargs (often written as **data or **info) in a function definition, Python collects all extra keyword arguments passed during the call.

It bundles these arguments into a single variable, which is a dictionary where the keyword names become the keys and their values become the dictionary values.

				
					def print_info(**kwargs):
    # kwargs inside the function is a dictionary: {'name': 'Carry', 'age': 30}
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Carry", age=30, city="New York")

				
			

Using **kwargs with regular arguments.

 

You can combine regular parameters with **kwargs.

				
					def process_order(item_name, **specifications):
    print(f"Order Item: **{item_name}**")
    print("Specifications:")
    
    # Corrected indentation (4 spaces)
    for key, value in specifications.items():
        # Corrected indentation for the loop body (8 spaces)
        print(f"  > {key.capitalize()}: {value}")

process_order("Pizza", size="Large", crust="Thin", toppings=["Mushrooms", "Pepperoni"], extra_cheese=True)

#    Order Item: **Pizza**
#    Specifications:
#    > Size: Large
#    > Crust: Thin
#    > Toppings: ['Mushrooms', 'Pepperoni']
#    > Extra_cheese: True

				
			

Combining *args and **kwargs

*args and **kwargs can be used at the same time but in the below mentioned order.

  1. regular parameters
  2. *args
  3. **kwargs
				
					def process_data(main_id, *values, **metadata):
    print("ID:", main_id)
    print("Values (Tuple):", values)
    print("Metadata (Dict):", metadata)

# Function Call:
process_data("A101", 10, 20, user='Jane', date='2025')

#   ID: A101
#   Values (Tuple): (10, 20)
#   Metadata (Dict): {'user': 'Jane', 'date': '2025'}

				
			

Function inside Function

It means defining a function inside the body of another function. The inner function is local to the outer function, meaning it can only be called from within the outer function’s body.

the inner function can access variables from the outer function’s scope, even after the outer function has finished executing.

				
					def greet_creator(name):
    # Inner function
    def greeting(message): 
        # The inner function accesses 'name' from the outer function's scope.
        print(f"{message}, {name}!") 
    greeting("Hello")
    greeting("Welcome back")
# Only the outer function can be called directly
greet_creator("Alice")

#   Hello, Alice!
#   Welcome back, Alice!

				
			

Outer Function: greet_creator(name) is defined and it takes one argument name(Alice)

Inner Function: greeting(message): ·  greeting(message) is defined inside greet_creator. It is only accessible within the body of greet_creator.

Enclosing Scope Access: The inner function greeting accesses the name variable (“Alice”) from the outer function’s (enclosing) scope.

Execution: The outer function calls the inner function twice passing a different message each time but always using the same name.

 

Pass by Value vs. Pass by Reference

 

Pass by Value: A copy of the argument’s value is passed to the function. Changes made to the parameter inside the function do not affect the original variable outside the function.

Pass by Reference: A reference (or memory address) to the original argument is passed.

Changes made to the parameter inside the function do affect the original variable outside the function.

				
					def object_assignment_demo(immutable_val, mutable_list):
    print(" Inside Function ")
    
    immutable_val = 999
    print(f"1. Immutable (Reassigned locally): {immutable_val}")

    mutable_list.append(4) 
    print(f"2. Mutable (Modified globally): {mutable_list}")

a = 10                  # Immutable integer
b = [1, 2, 3]           # Mutable list

print(f"Before function call: a={a}, b={b}")

object_assignment_demo(a, b)
print(f"After function call: a={a}, b={b}")


#   Before function call: a=10, b=[1, 2, 3]
#    Inside Function 
#   1. Immutable (Reassigned locally): 999
#   2. Mutable (Modified globally): [1, 2, 3, 4]
#   After function call: a=10, b=[1, 2, 3, 4]

				
			

Immutable (a): The value remains 10 outside the function (Pass by Value).

Mutable (b): The list is permanently changed to [1, 2, 3, 4] outside the function (Pass by Reference).

 

Returning Multiple Values

Functions can return multiple values using tuples:

				
					def calculate(a, b):
    sum_ = a + b
    diff = a - b
    return sum_, diff

s, d = calculate(10, 5)
print("Sum:", s)
print("Difference:", d)

# output

Sum: 15
Difference: 5

				
			

Changes made to the parameter inside the function do affect the original variable outside the function.

FAQ (Frequently Asked Questions)

1) What Is a Lambda Function in Python?

A lambda function is a small, anonymous function defined in one line.

square = lambda x: x * x
print(square(5))

# Output: 25

 

2) How to Use the random Function in Python?

In order to use it we should first import the random module

random.randint(1, 10)           #Creates a random integer between 1-10
random.random()                  # creates a random float from 0–1
random.choice([‘a’,’b’])          # choses a random item from list 
random.shuffle(list)              # Shuffle the items in a list
random.randrange(1, 20, 2) # returns a random number from specified range

 

3) What Does the strip() Function Do in Python?

strip() removes leading and trailing spaces from a string.

text = ”  hello world  “
print(text.strip())
# “hello world”

 

4) What is the Use of the print() Function in Python?

The print() function is used to display the output of the function. It helps in debugging, showing results and checking variable values.

 

5) What Is the reduce Function in Python?

reduce() applies a function to a sequence reducing it to a single value. It must import it from functools.

from functools import reduce

numbers = [1, 2, 3, 4]

result = reduce(lambda x, y: x + y, numbers)
print(result)

# Output: 10

 

6) What Is a Fruitful Function in Python?

A fruitful function is a function that returns a value.

def add(a, b):
return a + b

 

7) What is the Python map Function?

The map() function applies a specified function to every item in an iterable (like a list or tuple) and returns a map object (an iterator) containing the results.

numbers = [1, 2, 3]
result = list(map(lambda x: x * 2, numbers))
print(result) # [2, 4, 6]

 

8) What Are the Advantages of Functions in Python?

  • Dictionaries store data as unique key-value pairs.
  • They are optimized for fast data lookup using a descriptive key (like a name).
  • They are used to represent records or objects with named attributes (e.g: a student’s profile).
  • Dictionaries are the main structure for handling JSON data from web APIs.
  • They enable quick checks for item existence (if key in dictionary)
  • They are essential for passing flexible keyword arguments (**kwargs) to functions.

 

9) Difference Between a Function and a Method in Python

FunctionMethod
Independent block of codeFunction that belongs to an object
Defined using def at module levelDefined inside a class
Called directly → function()Called with object → object.method()
Example: len(x)Example: "hello".upper()