Python allows developers to create reusable and modular code by defining custom functions. Functions are one of the core building blocks of Python programming. They help break large programs down into smaller, more manageable pieces that can be called whenever needed. In this guide, we will learn how to define custom functions in Python, provide parameters and return values, include documentation, raise exceptions, and use best practices when creating functions.
Table of Contents
Open Table of Contents
Function Basics
A function in Python is defined using the def
keyword, followed by the function name and parameters in parentheses. The code to be executed is indented in the next lines. Here is the basic syntax:
def function_name(param1, param2):
"""Function documentation string"""
# Function body
return value
function_name
- A descriptive name summarizing what the function does. Follows variable naming conventions.param1, param2
- Parameters passed to the function. These are variable names that will be available in the function body."""documentation string"""
- An optional docstring describing what the function does. Used for documentation.return value
- An optional return statement to send a value back to the caller.
To call the function, simply use the function name with required parameters:
result = function_name(arg1, arg2)
Let’s see an example function definition that adds two numbers:
def add(num1, num2):
"""Adds two numbers together."""
sum = num1 + num2
return sum
result = add(5, 3)
print(result) # 8
Function Parameters
Parameters allow passing data into a function so it can operate on it. They act as variables that are initialized to the values passed in. Any immutable data types like numbers, strings, tuples can be used as parameters.
Parameters are defined in the function definition by naming each parameter separated by a comma. These named parameters become variables accessible in the function body.
For example, a function to calculate area of a circle requires a radius parameter:
def circle_area(radius):
pi = 3.14159
area = pi * radius * radius
return area
Here we have a single radius
parameter that the function uses to calculate the area.
We can also specify default values for parameters so caller can optionally pass them:
def insert_data(name, age=25):
print(f"Name: {name}, Age: {age}")
insert_data("John") # Uses default age
# Name: John, Age: 25
insert_data("Mary", 30) # Passes age
# Name: Mary, Age: 30
Positional vs Keyword Arguments
When calling a function in Python, arguments can be passed in two ways:
-
Positional Arguments - Based on position of parameter in function definition.
-
Keyword Arguments - By specifying parameter name with values.
For example:
def full_name(first, last):
print(f"{first} {last}")
full_name("John", "Doe") # Positional
full_name(first="John", last="Doe") # Keyword
Keyword arguments provide more explicit and readable function calls. The order also does not matter when using keyword arguments.
Return Values
The return
statement is used to return a value from the function back to the caller. This is helpful when we want to reuse the output of a function.
For example:
def multiply(a, b):
result = a * b
return result
x = multiply(2, 3)
print(x) # 6
We can return any object like numbers, strings, lists, dictionaries from a function in Python.
Return statements are optional. If no return statement is defined, Python automatically returns None
.
Docstrings
Docstrings in Python are string literals that are used to document functions, modules, and classes. They describe what the function does and how to use it.
Docstrings are defined as the first statement after the function definition, before any other code.
Docstring Format
"""Summary line describing function
Extended description explaining the function's purpose, parameters,
return values, side effects, etc.
Any other relevant details.
"""
- The docstring starts and ends with triple quotes.
- The first line should be a short concise summary of the function.
- An empty line follows the summary before the extended description.
- Paragraphs in the long description should be wrapped to 72 characters.
- Closing triple quote should be on its own line.
Let’s add a docstring to our circle_area()
function:
def circle_area(radius):
"""Calculates and returns the area of a circle given radius."""
pi = 3.14159
area = pi * radius * radius
return area
We can access the docstring of a function using the __doc__
attribute:
print(circle_area.__doc__)
# Calculates and returns the area of a circle given radius.
Including high quality docstrings is considered a best practice in Python as they help document our code.
Default Arguments
We can specify a default value for a parameter by using an assignment in the function definition:
def log(message, type='INFO'):
print(f"{type}: {message}")
Here if the type
parameter is not passed, it takes the default value 'INFO'
.
Default values should be used judiciously after careful consideration. Overuse of default arguments can make code difficult to understand.
All parameters with default values must be listed after parameters without default values in the function definition.
Variable Scope
Parameters and variables declared inside a function only exist within the local scope of that function. They cannot be referenced outside the function. For example:
def calculate_sum(x, y):
total = x + y # Local variable
return total
print(total) # ERROR, total not defined
The total
variable only exists within the calculate_sum()
function.
However, a function can access global variables declared outside the function. But it is not a good practice as it can lead to unintended consequences.
Best Practices for Functions
Here are some key best practices to follow when defining Python functions:
- Use descriptive names that summarize what the function does.
- Limit functions to a single coherent purpose. Break into smaller functions if needed.
- Use parameters instead of global variables for passing data into functions.
- Add docstrings for documentation and clarity.
- Specify default values carefully for parameters that are likely to be frequently reused.
- Avoid unintended side effects that modify mutable arguments passed in.
- Avoid excessive use of global variables within functions. Use parameters instead.
- Return meaningful results rather than relying on side effects for primary results.
Common Built-in Functions
Python provides many in-built functions that are readily available for use. Some commonly used built-in functions include:
print()
- Print output to consolelen()
- Get length of an objectmax()/min()
- Get maximum or minimum element of iterableinput()
- Read user inputint()/float()/str()
- Type conversion functionsopen()
- Open file and return file objectrange()
- Generate a numeric rangeenumerate()
- Return enumerate object of iterablezip()
- Combine iterables into zip object
These in-built functions implement core functionality that is frequently required in programs. We can simply call them rather than re-implementing similar logic ourselves.
User-defined vs Built-in Functions
User-defined functions are created by developers while built-in functions come packaged with Python.
Some key differences:
- User-defined - Custom logic, specific to problem, meaningful names.
- Built-in - General purpose, common logic, fixed names.
- User-defined functions must be defined before being called. Built-ins are always available.
- Can redefine user functions. Built-ins cannot be redefined.
- Built-ins are implemented in C for speed. User functions interpreted.
In general, use user-defined functions to encapsulate custom program logic and built-ins for generic operations.
Raising Exceptions
Exceptions provide a way to handle errors and anomalous situations in our programs. In Python, exceptions are raised when an error occurs and can be handled using try
and except
blocks.
We can also manually raise exceptions in our functions using the raise
keyword:
def validate_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
if age > 200:
raise ValueError("Age too large")
validate_age(-10) # Raises ValueError
The raise
statement stops function execution and throws the specified exception. This exception can be handled by the caller.
Common built-in exceptions used with raise
include:
ValueError
- Invalid argument value passedTypeError
- Argument of invalid type passedIOError
- Input/Output error occurredZeroDivisionError
- Divide by zero occurredKeyboardInterrupt
- User interrupted execution
Manual exception raising makes code cleaner by separating validation logic from regular code. The caller is forced to handle validation failures explicitly rather than relying on return codes or status flags.
Recursive Functions
Python supports recursive functions, which are functions that call themselves during execution. This is useful for algorithms that can be defined recursively like sorting, traversal, etc.
For example, calculating factorial of a number recursively:
def factorial(x):
if x == 1:
return 1
else:
return x * factorial(x-1)
print(factorial(5)) # 120
- A recursive function must have a terminating condition that stops the recursion, like
x == 1
above. - Multiple recursive calls create a deep call stack that requires O(n) memory.
- Recursive solutions must be transformed to iterative ones for large inputs that cause stack overflow.
Anonymous/Lambda Functions
Python supports small anonymous functions that are not bound to a name using the lambda
keyword:
double = lambda x: x * 2
print(double(7)) # 14
- Lambda functions can only do simple expressions not multiple lines.
- Accepted wherever function objects are required.
- Used as anonymous, in-line functions for brevity.
- Very commonly used in map, reduce, filter type higher order functions.
Conclusion
Defining custom functions is a critical skill in Python for writing reusable code. Functions encapsulate logic, take parameters and return results. Docstrings provide documentation while exceptions handle errors. Following best practices for naming, scope and signatures improves code quality. Built-in functions offer commonly used utilities. Recursive functions and lambdas provide additional capabilities. With this comprehensive guide, you should feel confident authoring custom functions in Python!