Python Functions

Introduction to Functions

Functions in Python are "self-contained" modules of code designed to perform a specific task. They allow developers to "take in" data, process it, and "return" a result. Functions provide an essential mechanism for reusability: once written, they can be invoked multiple times without duplicating the code. For instance, a function that prints a greeting can be used for different inputs:

def hello(name):
    print('Hello, ' + name)
hello('Alice')
hello('Class')
Hello, Alice
Hello, Class

Basic Usage of Python Functions

The structure of a Python function consists of a `def` keyword, the function name, parameters, a body, and an optional return statement. Here is an example of a simple function with parameters:

def addup(num1: int, num2: int, num3: int) -> int:
    """Add three numbers"""
    y = num1 + num2 + num3
    return y

num1, num2, num3 = 5, 15, 35
ans = addup(num1, num2, num3)
print(f"The addition of {num1}, {num2}, and {num3} results in {ans}.")

Returning Multiple Parameters

Python functions can return multiple values, which can then be assigned to separate variables. For example:

def arithmetic(num1, num2):
    add = num1 + num2
    sub = num1 - num2
    multiply = num1 * num2
    division = num1 / num2
    return add, sub, multiply, division

a, b, c, d = arithmetic(10, 2)
print("Addition:", a)
print("Subtraction:", b)
print("Multiplication:", c)
print("Division:", d)

Default Arguments in Functions

Functions can also have default arguments, which provide a fallback value if no argument is supplied:

def simplePrints(x, y: int = 50):
    print("x:", x)
    print("y:", y)

simplePrints(10)
simplePrints(10, 20)

Keyword Arguments

Keyword arguments allow the caller to specify argument names, making the code more readable:

def student(firstname, lastname):
    print(firstname, lastname)

student(firstname='Paul', lastname='Atredies')
student(lastname='Atredies', firstname='Paul')

Variable Arguments

Python functions can accept a variable number of arguments using `*args` and `**kwargs`:

def some_function(*args, **kwargs):
    print(f"Args: {args}")
    print(f"Kwargs: {kwargs}")

some_function(0, 1, 2, 3, a=4, b=5, c=6)
Args: (0, 1, 2, 3)
Kwargs: {'a': 4, 'b': 5, 'c': 6}

Anonymous Functions / Lambda Functions

Lambda functions are small, unnamed functions defined using the `lambda` keyword. They are often used for short, simple operations:

import math
etapp_v2 = lambda t: 1 + t + t*t/2 + t*t*t/6
print(etapp_v2(0.2))  # Approximation of e^0.2
print(math.e**0.2)    # Actual value of e^0.2

The Pass Statement

The `pass` statement is a placeholder that does nothing. It is useful for writing code stubs during development:

def addition(num1, num2):
    pass  # Implementation coming soon

addition(10, 2)

Pass by Reference and Pass by Value

In Python, variable names are references to data. Changes to mutable objects inside a function affect the original data:

def myFun(x):
    x[-1] = 10
lst = [i for i in range(5)]
print(lst)
myFun(lst)
print(lst)
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 10]

However, reassigning the reference inside a function breaks the connection:

def myFun2(x):
    x = 10
lst = [i for i in range(5)]
print(lst)
myFun2(lst)
print(lst)

Exception Handling

Python provides a robust mechanism for handling exceptions using `try` and `except` blocks:

def get_ratio(x: int, y: int) -> float:
    try:
        return x / y
    except ZeroDivisionError:
        print('Denominator cannot be zero. Adjusting it to 0.00001.')
        return x / (y + 0.00001)

print(get_ratio(400, 0))

Putting It All Together: Fizz Buzz Game

The Fizz Buzz game demonstrates functions and loops in action. Players count upwards, replacing numbers divisible by 3 with "Fizz," by 5 with "Buzz," and by both 3 and 5 with "FizzBuzz":

def fizz_buzz_game(n: int = 10):
    for i in range(1, n + 1):
        if i % 3 == 0 and i % 5 == 0:
            print("FizzBuzz")
        elif i % 3 == 0:
            print("Fizz")
        elif i % 5 == 0:
            print("Buzz")
        else:
            print(i)

fizz_buzz_game(15)