Functions and modules are essential building blocks in Python, allowing developers to write reusable, organized, and maintainable code. Functions encapsulate logic, while modules package related functions and data together.
Functions in Python
A function in Python is a block of reusable code designed to perform a specific task. Functions take inputs, process them, and return an output. Functions can be used to organize your code, avoid repetition, and make the program easier to read and maintain.
Defining Functions:
Functions are defined using the def keyword:
def add(a: int, b: int) -> int:
"""Adds two numbers and returns the result."""
return a + b
# Calling the function
result = add(2, 3)
print(result) # Outputs: 5
In this example: - The function add takes two arguments (a and b) and returns their sum. - Type hints(a: int, b: int, and -> int) specify the expected types of the input and output. - The ”““docstring”“” describes the function, which is useful for documentation.
Function Parameters
Python functions can have different kinds of parameters:
- Positional parameters: Parameters passed in order.
def greet(name: str) -> None:
print(f”Hello, {name}!“)
greet(“Alice”) # Hello, Alice!
- Default parameters: Parameters with default values.
def greet(name: str = "World") -> None:
print(f"Hello, {name}!")
greet() # Outputs: Hello, World!
- Arbitrary arguments(*args) and keyword arguments (**kwargs):
def print_args(*args: int) -> None:
for arg in args:
print(arg)
print_args(1, 2, 3) # Outputs: 1 2 3
def print_kwargs(**kwargs: str) -> None:
for key, value in kwargs.items():
print(f"{key}: {value}")
print_kwargs(name="Alice", age="25") # Outputs: name: Alice age: 25
Higher-Order Functions
A higher-order function is a function that takes another function as an argument or returns a function.
def square(x: int) -> int:
return x * x
def apply_function(func, x: int) -> int:
return func(x)
# Passing the `square` function as an argument
result = apply_function(square, 5)
print(result) # Outputs: 25
Higher-order functions are often used in functional programming and for operations like map, filter, and reduce.
Anonymous Functions (Lambdas)
Python supports lambda functions, which are small, anonymous functions defined without the def keyword. They are typically used for short, simple functions.
# Lambda function to add two numbers
add_lambda = lambda a, b: a + b
# Using the lambda function
result = add_lambda(2, 3)
print(result) # Outputs: 5
Lambda functionsare useful when you need a simple function for a short period and don’t want to formally define it with def.
Closures
A closure is a function that remembers the environment in which it was created. This allows a function to access variables from its enclosing scope, even after that scope has finished execution.
def outer_func(x: int):
def inner_func(y: int):
return x + y
return inner_func
add_5 = outer_func(5)
print(add_5(10)) # Outputs: 15
In this example, inner_funcremembers the value of x from outer_func, even though outer_funchas finished executing.
Common Mistakes
- Mutating Default Arguments: Python’s default arguments are evaluated once when the function is defined, not each time the function is called. This can lead to unexpected behavior when using mutable types (like lists or dictionaries).
def append_to_list(value, my_list=[]):
my_list.append(value)
return my_list
print(append_to_list(1)) # [1]
print(append_to_list(2)) # [1, 2] -> Surprise!
- Misusing return: Forgetting to use return can lead to None being returned.
def add(a, b):
result = a + b # No return statement!
print(add(1, 2)) # Outputs: None
Modules in Python
A module in Python is a file that contains Python code (functions, classes, variables). Modules allow you to logically organize your code and reuse it across different programs. Python’s extensive standard library is made up of numerous built-in modules, and you can create your own modules.
Importing Modules
You can import an entire module or specific parts of it using the import statement.
# Importing an entire module
import math
print(math.sqrt(16)) # Outputs: 4.0
# Importing specific functions
from math import sqrt
print(sqrt(16)) # Outputs: 4.0
Creating Your Own Module
To create your own module, write Python code in a .py file and import it into another script.
Example (my_module.py):
def greet(name: str) -> None:
print(f"Hello, {name}!")
Usage(main.py):
import my_module
my_module.greet("Alice") # Outputs: Hello, Alice!
Module Search Path
When you import a module, Python searches for it in the directories listed in sys.path:
import sys
print(sys.path) # Lists directories where Python looks for modules
If the module isn’t found in any of these directories, an ImportErroris raised.
Packages
A package is a directory that contains multiple modules, usually organized under a single namespace. A package contains an __init__.py file, which can be empty or contain initialization code for the package.
Example Directory Structure:
my_package/
__init__.py
module1.py
module2.py
You can import a module from a package like this:
from my_package import module1