Basics of Functions in Python: A detailed guide
Functions are the fundamental building block of any serious program. They allow you to package repetitive code into a single named block that can be called repeatedly from different parts of the program. This not only saves space, but also makes the code more readable, organized, and easy to debug.
Function definition
The function is defined using the keyword def, followed by the function name, parentheses (in which arguments are specified) and a colon. The body of the function is the entire indented code under this line.
A useful tip: Immediately after defining a function, it is customary to write a docstring in triple quotes. It describes what the function does, what arguments it accepts, and what it returns. This is the standard of good taste in programming.
def function_name(arguments):
"""
This is a docstring.
It explains the function's purpose.
"""
# body
of the return result function
Example of a simple function:
def greet_user():
"""This function outputs a simple greeting."""
print("Hello world!")
# function call
greet_user() # Output: Hello world!
Function arguments
The arguments are the data that you pass to the function for processing.
1. Positional arguments
These are the simplest arguments. They are passed to the function in order. Their position when calling a function is crucial.
def subtract(a, b):
"""Subtracts the second argument from the first."""
return a - b
print(subtract(10, 3)) # Output: 7
print(subtract(3, 10)) # Conclusion: -7 (order is important!)
2. Named arguments (keywords)
These are arguments passed to the function by name. They allow you to set values in any order and make the code clearer, especially if the function has many arguments.
def descripe_pet(animal_type, pet_name):
"""Displays information about the pet."""
print(f"I have {animal_type}.")
print(f"His name is {pet_name}.")
# The order is not important when using named arguments
of descripe_pet(pet_name="Murzik", animal_type="cat")
# Conclusion:
# I have a cat.
# His name is Murzik.
3. Default arguments
These are arguments that are assigned a value right in the function definition. If no value is passed for such an argument when calling the function, the default value is used. This makes some arguments optional.
def greet(name, message="Hello"):
""" Greets the user using a standard message."""
print(f"{message}, {name}!")
hello("Alice") # The default value is used. Conclusion: Hello, Alice!
hello ("Bob", "Welcome") # The default value has been redefined. Conclusion: Welcome, Bob!
Important advice: Never use mutable data types (for example, lists [] or dictionaries {}) as default values. They are created once when defining a function and can lead to unexpected behavior.
4. Any number of arguments (*args and **kwargs)
Sometimes you don't know in advance how many arguments you will need to pass.
*args collects all passed positional arguments into a tuple.
**kwargs collects all passed named arguments into a dict.
def calculate_sum(*args):
"""Sums an arbitrary number of numbers."""
print(f"Received numbers (tuple): {args}")
return sum(args)
print(calculate_sum(1, 2, 3, 4, 5)) # Output: The resulting numbers (tuple): (1, 2, 3, 4, 5) and then 15
def display_info(**kwargs):
""" Displays information in key-value format."""
print(f"Received data(dictionary): {kwargs}")
for key, value in kwargs.items():
print(f"{key}: {value}")
display_info(name="Alice", age=30, city="Moscow")
# Output:
# Received data (dictionary): {'name': 'Alice', 'age': 30, 'city': 'Moscow'}
# name: Alice
# age: 30
# city: Moscow
Returning values
The function can return the result of its operation using the return operator. As soon as return is triggered, the function execution stops immediately. If return is not specified, the function implicitly returns None.
def multiply(a, b):
"""Multiplies two numbers and returns the result."""
return a * b
print("This code will never run") # The line after return is unreachable
result = multiply(3, 4)
print(result) # Output: 12
A useful tip: The function can return multiple values. Technically, it returns a single tuple, which can be conveniently decompressed into several variables.
def get_user_data():
name = "Ivan"
age = 25
return name, age # The motorcade returns (Ivan, 25)
user_name, user_age = get_user_data() # Unpacking the tuple
print(f"Name: {user_name}, Age: {user_age}") # Output: Name: Ivan, Age: 25
Variable scopes
- Local viewport: Variables defined inside a function "live" only inside it and are destroyed after its completion.
- Global viewport: Variables defined outside of all functions are available in any part of the program.
global_var = "I am a global variable"
def my_function():
local_var = "I am a local variable"
print(global_var) # Access to the global variable
print(local_var)
my_function()
# Output:
# I am a global variable
# I am a local variable
# print(local_var) # Error NameError: name 'local_var' is not defined
The Council: To change a global variable inside a function, use the keyword global. However, try to avoid this, as it makes debugging more difficult. It is better to pass values through arguments and return the result through return.
Recommendations for naming functions
-
Descriptive names: The name should say what the function does. calculate_tax is better than calc.
-
Style snake_case: In Python, it is common to use lowercase letters with words separated by underscores (my_cool_function).
-
Use verbs: Functions perform actions, so their names often begin with verbs: get_data, send_message, validate_input, is_active.
-
Type Hints: Modern Python allows you to specify the types of expected arguments and return values. This does not affect the execution, but it greatly improves readability and helps to find errors.
# This function expects two integers and returns an integer
def add_numbers(a: int, b:int) -> int:
return a + b