Functions

Functions are named blocks of code that perform a specific task. They allow you to organize your code, make it more readable, and avoid code duplication. By defining functions, you can break down complex problems into smaller, manageable units. In this unit, we'll delve into the concept of functions, explore how to define and call them, and discuss the importance of parameter passing and return values.

Defining Functions


Defining a function involves giving it a name and writing the code that will be executed when the function is called.

def function_name():
    """Docstring: A brief description of the function's purpose"""
    # Function body: The code to be executed

Breakdown:

  1. def keyword: This keyword signifies the start of a function definition.
  2. function_name: This is the name you give to your function. It should be descriptive and follow Python's naming conventions.
  3. (): Empty parentheses indicate that the function doesn't take any input parameters.
  4. Docstring: This is an optional documentation string that explains what the function does. It's a good practice to include docstrings for better code readability and maintainability.
  5. Function body: This is where you write the actual code that the function will execute. It can include any valid Python statements, such as variable assignments, calculations, conditional statements, loops, and function calls.
## FUNCTION EXAMPLE ##
def greet():
    """Greets the user with a simple message."""
    print("Hello, World!")

# Calling the function
greet()
Hello, World!

Key Points:

  • Function Calling: To execute a function, you simply write its name followed by parentheses.
  • Modularity: Functions help break down complex problems into smaller, more manageable parts, making your code more organized and easier to understand.
  • Reusability: Once a function is defined, it can be called multiple times from different parts of your program, saving you from writing the same code repeatedly.

Parameters


In Python, parameters are variables that a function can accept as input. They act as placeholders for values that you can pass to the function when you call it. This allows you to make your functions more flexible and reusable.

def function_name(parameter1, parameter2, ...):
    # Function body

Breakdown:

  1. parameter1, parameter2, ...: These are the names of the parameters that the function can accept. You can define as many parameters as you need.
  2. Function body: This is where you write the code that will use the values of the parameters. You can reference the parameters within the function body using their names.

Key Points:

  • Argument Passing: When you call a function, you provide values for the parameters, which are called arguments.
  • Positional Arguments: By default, arguments are matched to parameters based on their position. The first argument is assigned to the first parameter, the second argument to the second parameter, and so on.
  • Keyword Arguments: You can also pass arguments using keyword arguments, where you specify the parameter name along with the value. This allows you to pass arguments in any order.
## FUNCTION w/ PARAMETERS EXAMPLE ##
def greet(name):
    print("Hello, " + name + "!")

# Calling the function with an argument
greet("Milo")
Hello, Milo!
## FUNCTION w/ KEYWORD ARGUMENTS EXAMPLE ##
def calculate_area(length, width):
    area = length * width
    print("Area:", area)

# Calling the function with keyword arguments
calculate_area(width=5, length=10)
Area: 50

Return Values


A return value is the output or result that a function produces. When a function reaches a return statement, it immediately exits and sends the specified value back to the part of the code that called it.

def function_name(parameter1, parameter2, ...):
    # Function body
    return value

Breakdown:

  1. return value: This statement specifies the value that the function will return. The value can be any Python object, such as a number, string, list, or even another function.
  2. Function Call: When you call a function that returns a value, you can assign the returned value to a variable or use it directly in an expression.

Key Points:

  • Early Return: You can use return to exit a function early, without executing the rest of the code.
  • Data Flow: Return values allow you to pass data from one function to another, enabling complex data processing pipelines.
  • Modular Design: Functions with return values can be used as building blocks to create larger programs.
  • Code Readability: By breaking down complex tasks into smaller functions with clear return values, you can improve code readability and maintainability.
## FUNCTION w/ RETURN VALUES EXAMPLE ##
def add_numbers(x, y):
    """Adds two numbers and returns the result."""
    return = x + y

# Calling the function and assigning the return value
result = add_numbers(5, 3)
print(result)
8

Local Variables


Local variables are variables that are declared and defined within a function. They are only accessible within the scope of that function and cease to exist once the function finishes execution.

def function_name(parameter1, parameter2, ...):
    # Local variable declaration
    local_variable = value

    # Function body

Breakdown:

  1. local variable: This is the name of the local variable.
  2. value: This is the initial value assigned to the local variable.

Key Points:

  • Scope: Local variables are only accessible within the function where they are defined. They cannot be accessed from outside the function.
  • Lifetime: Local variables are created when the function is called and are destroyed when the function returns.
  • Multiple Functions: Different functions can have local variables with the same name without interfering with each other.
## FUNCTION w/ LOCAL VARIABLE EXAMPLE ##
def add_numbers(x, y):
    """Adds two numbers and returns the result."""
    num_sum = x + y # num_sum is a local variable
    return num_sum

# Calling the function and assigning the return value
result = add_numbers(5, 3)
print(result)
8

Exceptions


In Python, exceptions are events that occur during program execution that disrupt the normal flow of control. They are often caused by errors in the code, such as trying to divide by zero, accessing an index out of range, or attempting to open a file that doesn't exist.

Why use exceptions?

  • Error Handling: Exceptions provide a structured way to handle errors and prevent your program from crashing.
  • Code Clarity: By separating error handling code from the main logic, you can make your code more readable and maintainable.
  • Custom Error Handling: You can define your own custom exceptions to signal specific error conditions.
try:
    # Code that might raise an exception
except ExceptionType:
    # Code to handle the exception

Breakdown:

  1. try block: This block contains the code that might raise an exception.
  2. except block: This block is executed only if an exception of the specified type occurs within the try block.
def divide(x, y):
    try:
        result = x / y
        return result
    except ZeroDivisionError:
        print("Error: Division by zero")
        return None

Common Exception Types:

  • ZeroDivisionError: Raised when you try to divide a number by zero.
  • ValueError: Raised when a built-in operation or function receives an argument that has the right type but an inappropriate value.
  • TypeError: Raised when an operation or function is applied to an object of an inappropriate type.
  • IndexError: Raised when a sequence subscript is out of range.
  • KeyError: Raised when a dictionary key is not found.
  • FileNotFoundError: Raised when a file or directory is not found.