Functions and Arguments¶
A function is a block of organized, reusable code that is used to perform a single, related action. Functions provide better modularity for your application and a high degree of code reusing.
Defining a Function¶
Functions are defined using the def keyword, followed by the function name and parentheses ().
Syntax¶
def function_name(parameters):
"""Docstring explaining function purpose."""
# function body
return value
def add_numbers(a: int, b: int) -> int:
"""Return the sum of a and b."""
return a + b
result = add_numbers(10, 20)
print("Result:", result)
Positional and Keyword Arguments¶
- Positional arguments: Arguments passed in the exact order declared in the function header.
- Keyword arguments: Arguments passed by specifying parameter names (
name=value).
def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type} named {pet_name}.")
# Positional
describe_pet("dog", "Buddy")
# Keyword (order does not matter)
describe_pet(pet_name="Whiskers", animal_type="cat")
Default Parameter Values¶
You can provide default values for parameters. If the caller does not supply an argument, the default is used:
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Alice")) # Hello, Alice!
print(greet("Bob", greeting="Hi")) # Hi, Bob!
Important Warning: Mutable Default Arguments¶
Default argument values are evaluated only once at the time of function definition. If you use a mutable object (like a list or dict) as a default, it will be shared across all calls:
# Problematic:
def bad_append(item, target_list=[]):
target_list.append(item)
return target_list
print(bad_append(1)) # [1]
print(bad_append(2)) # [1, 2] (Shared across calls!)
# Correct Idiomatic Pattern:
def good_append(item, target_list=None):
if target_list is None:
target_list = []
target_list.append(item)
return target_list
print(good_append(1)) # [1]
print(good_append(2)) # [2] (Independent)
Special Parameters: Positional-Only (/) and Keyword-Only (*)¶
In Python 3.8+, you can control whether arguments must be passed by position, by keyword, or either:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
def configure(host, port, /, timeout=30, *, secure=True):
print(f"{host}:{port} (timeout={timeout}, secure={secure})")
# Valid:
configure("localhost", 8000, 60, secure=False)
configure("localhost", 8000, timeout=60, secure=True)
# Invalid:
# configure(host="localhost", port=8000) # TypeError: host is positional-only
# configure("localhost", 8000, 30, True) # TypeError: secure is keyword-only
Arbitrary Arguments: *args and **kwargs¶
*args: Collects extra positional arguments into a tuple.**kwargs: Collects extra keyword arguments into a dictionary.
def display_info(title, *args, **kwargs):
print("Title: ", title)
print("Args: ", args)
print("Kwargs:", kwargs)
display_info("Server Status", "active", "verified", ip="127.0.0.1", port=8080)
Lambda Functions (Anonymous Functions)¶
A lambda function is a small anonymous function defined using the lambda keyword. It can take any number of arguments, but can only have one expression: