Python Functions
Python Functions
Section titled “Python Functions”A function is a named block of reusable code designed to perform a specific task. Functions help organize code, make applications more modular, improve readability, and promote code reuse.
Python provides many built-in functions (e.g., print(), len(), type()). You can also define your own functions, known as user-defined functions.
Defining a Function
Section titled “Defining a Function”Functions are defined using the def keyword, followed by the function name, parentheses (), and a colon :. The code block within the function must be indented.
- Syntax starts with
def function_name(parameters):. - Parameters (inputs to the function) are listed inside the parentheses, separated by commas. A function can have zero or more parameters.
- The first statement can be an optional documentation string (docstring), enclosed in triple quotes (
"""Docstring goes here"""), explaining what the function does. This is highly recommended. - The indented code block following the colon is the function body (suite).
- The
returnstatement exits the function and optionally sends a value back to the caller. Ifreturnis omitted or used without an expression, the function implicitly returnsNone.
Syntax
Section titled “Syntax”def function_name(parameter1, parameter2=default_value): """Optional docstring explaining the function.""" # Function body (indented code) result = parameter1 + parameter2 return result # Optional return statementExample
Section titled “Example”A simple function that takes a name and prints a greeting:
def greet(name): """Prints a simple greeting to the given name.""" print(f"Hello, {name}!") # Implicitly returns NoneCalling a Function
Section titled “Calling a Function”Defining a function doesn’t execute it. To run the code inside a function, you must call it by using its name followed by parentheses, providing any required arguments.
# Define the function firstdef greet(name): """Prints a simple greeting.""" print(f"Hello, {name}!")
# Now call the functiongreet("Alice")greet("Bob")Output:
Hello, Alice!Hello, Bob!Argument Passing (Pass by Object Reference)
Section titled “Argument Passing (Pass by Object Reference)”In Python, arguments are passed using a mechanism sometimes called “pass by object reference” or “pass by assignment”. Here’s what it means:
Example (Mutable Object):
def modify_list(my_list): """Appends an item to the passed list.""" my_list.append(100) # Modifies the original list object print(f"Inside function: {my_list}")
numbers = [10, 20, 30]modify_list(numbers)print(f"Outside function: {numbers}") # The change persistsOutput:
Inside function: [10, 20, 30, 100]Outside function: [10, 20, 30, 100]Example (Reassignment):
def reassign_list(my_list): """Reassigns the parameter to a new list.""" my_list = [1, 2, 3, 4] # Parameter now points to a *new* list print(f"Inside function (after reassign): {my_list}")
numbers = [10, 20, 30]reassign_list(numbers)print(f"Outside function: {numbers}") # Original list is unaffectedOutput:
Inside function (after reassign): [1, 2, 3, 4]Outside function: [10, 20, 30]Function Arguments Types
Section titled “Function Arguments Types”Python offers flexible ways to define and call functions with different argument types:
1. Positional Arguments
Section titled “1. Positional Arguments”These are the standard arguments, matched based on their order. The number of arguments in the call must match the number of parameters.
def describe_pet(animal_type, pet_name): print(f"I have a {animal_type} named {pet_name}.")
describe_pet("hamster", "Harry") # Correct order# describe_pet("Fluffy") # TypeError: missing 1 required positional argument: 'pet_name'2. Keyword Arguments
Section titled “2. Keyword Arguments”You can specify arguments by parameter name in the function call. This allows you to pass arguments out of order and improves clarity.
def describe_pet(animal_type, pet_name): print(f"I have a {animal_type} named {pet_name}.")
describe_pet(pet_name="Willie", animal_type="dog") # Order doesn't matterdescribe_pet(animal_type="cat", pet_name="Whiskers")3. Default Argument Values
Section titled “3. Default Argument Values”You can provide default values for parameters in the function definition. If an argument for that parameter is not provided in the call, the default value is used. Parameters with default values must come after parameters without defaults.
def describe_pet(pet_name, animal_type="dog"): # default for animal_type print(f"I have a {animal_type} named {pet_name}.")
describe_pet(pet_name="Buddy") # Uses default animal_type 'dog'describe_pet(pet_name="Lucy", animal_type="cat") # Overrides defaultOutput:
I have a dog named Buddy.I have a cat named Lucy.4. Variable-Length Arguments (*args)
Section titled “4. Variable-Length Arguments (*args)”To allow a function to accept an arbitrary number of positional arguments, use an asterisk * before a parameter name (conventionally *args). This collects any extra positional arguments into a tuple.
def make_pizza(size, *toppings): """Prints the pizza being ordered with its toppings.""" print(f"\nMaking a {size}-inch pizza with the following toppings:") if toppings: for topping in toppings: print(f"- {topping}") else: print("- Plain")
make_pizza(12, "mushrooms")make_pizza(16, "pepperoni", "green peppers", "extra cheese")make_pizza(10) # No extra positional args, toppings tuple is emptyOutput:
Making a 12-inch pizza with the following toppings:- mushrooms
Making a 16-inch pizza with the following toppings:- pepperoni- green peppers- extra cheese
Making a 10-inch pizza with the following toppings:- Plain5. Variable-Length Keyword Arguments (**kwargs)
Section titled “5. Variable-Length Keyword Arguments (**kwargs)”To allow a function to accept an arbitrary number of keyword arguments, use two asterisks ** before a parameter name (conventionally **kwargs). This collects any extra keyword arguments into a dictionary.
def build_profile(first, last, **user_info): """Builds a dictionary containing user information.""" profile = {'first_name': first, 'last_name': last} profile.update(user_info) # Add any extra kwargs return profile
user1 = build_profile('albert', 'einstein', location='princeton', field='physics')user2 = build_profile('marie', 'curie', field='chemistry', awards=2)
print(user1)print(user2)Output:
{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}{'first_name': 'marie', 'last_name': 'curie', 'field': 'chemistry', 'awards': 2}6. Keyword-Only Arguments (Python 3)
Section titled “6. Keyword-Only Arguments (Python 3)”Arguments placed after *args or a bare * must be specified using keywords.
def process_data(*, input_file, output_file, force=False): """Requires input_file and output_file to be passed by keyword.""" print(f"Processing {input_file} to {output_file}. Force={force}")
# process_data("in.txt", "out.txt") # TypeError!process_data(input_file="in.csv", output_file="out.csv")process_data(input_file="data.zip", output_file="proc.zip", force=True)7. Positional-Only Arguments (Python 3.8+)
Section titled “7. Positional-Only Arguments (Python 3.8+)”Arguments placed before a bare / can only be specified by position, not keyword.
def example_pos_only(a, b, / , c, d): """a and b are positional-only.""" print(f"a={a}, b={b}, c={c}, d={d}")
example_pos_only(1, 2, c=3, d=4) # Works# example_pos_only(a=1, b=2, c=3, d=4) # TypeError! a and b are positional-onlyLambda (Anonymous) Functions
Section titled “Lambda (Anonymous) Functions”Lambda functions provide a shorthand syntax for creating small, anonymous functions (functions without a name). They are defined using the lambda keyword.
- Syntax:
lambda arguments: expression - Can take any number of arguments but can only have one expression.
- The expression is evaluated and returned when the lambda is called.
- Often used where a simple function object is required (e.g., as arguments to
map(),filter(),sorted()).
Example:
# Equivalent to: def add(x, y): return x + yadder = lambda x, y: x + y
print(f"Value of total: {adder(10, 20)}")print(f"Value of total: {adder(5, -2)}")
# Using lambda with sorted()points = [(1, 2), (3, 1), (5, -4), (2, 3)]# Sort points based on the second element (y-coordinate)points_sorted_by_y = sorted(points, key=lambda point: point[1])print(f"Sorted by y: {points_sorted_by_y}")Output:
Value of total: 30Value of total: 3Sorted by y: [(5, -4), (3, 1), (1, 2), (2, 3)]The return Statement
Section titled “The return Statement”The return statement is used to exit a function and send a value back to where the function was called. A function can return any type of object.
def subtract(arg1, arg2): """Subtracts arg2 from arg1 and returns the result.""" total = arg1 - arg2 print(f"Inside the function, result: {total}") return total
# Call the function and store the returned valueresult_value = subtract(20, 5)print(f"Outside the function, result: {result_value}")
# Can return multiple values (as a tuple)def get_coordinates(): return 10, 20 # Automatically packed into a tuple
x, y = get_coordinates() # Unpack the returned tupleprint(f"Coordinates: x={x}, y={y}")Output:
Inside the function, result: 15Outside the function, result: 15Coordinates: x=10, y=20Variable Scope (LEGB Rule)
Section titled “Variable Scope (LEGB Rule)”The scope of a variable determines where in the program it can be accessed.
Python searches for a variable name in this LEGB order.
total = 0 # Global variable
def sum_and_update(arg1, arg2): # 'total' inside here refers to a *new* local variable # unless declared global # global total # Uncomment this to modify the global 'total' total = arg1 + arg2 # Creates a local 'total', shadows the global one print(f"Inside function local total: {total}") return total
sum_and_update(10, 20)print(f"Outside function global total: {total}") # Global 'total' remains unchangedOutput (without global total uncommented):
Inside function local total: 30Outside function global total: 0Type Hinting (PEP 484)
Section titled “Type Hinting (PEP 484)”Modern Python (3.5+) supports optional type hints, allowing you to annotate function parameters and return values with their expected types. Type hints do not affect runtime behavior but are invaluable for static analysis tools (like MyPy), IDEs, and improving code clarity.
import math
def calculate_circumference(radius: float) -> float: """Calculates the circumference of a circle given its radius.""" if radius < 0: raise ValueError("Radius cannot be negative") return 2 * math.pi * radius
# Type hints help catch potential errors staticallycircum = calculate_circumference(10.5)print(f"Circumference: {circum:.2f}")
# Mypy would flag this call if run:# result_wrong_type = calculate_circumference("hello")Common types are imported from the typing module (e.g., List, Dict, Tuple, Optional).