skip to content
Ratuls['Blog']

Basic functional programming in Python

// And why the func should you care?!



What is a function?

A function is a block of code that is executed when it is called. It can take parameters and return a value. It is a way to create reusable code.

Why use functions?

Functions are useful for creating reusable code. They can be used to perform a specific task. They can also be used to perform a specific task multiple times or to perform a specific task multiple times with different parameters.

Built-in functions

Python has a number of built-in functions. These are functions that are already defined in the Python language. They can be used without having to define them. Some of the most common built-in functions are:

  • print() which prints it’s arguments to the screen,
  • input() which takes input from the user,
  • len() which returns the length of an object,
  • type() which returns the type of an object, and many others.

User-defined functions

User-defined or ‘regular’ functions in python are custom functions which we can create with the def keyword.

Arguments and return values

User-defined functions can take arguments and return values. The return keyword is used to return a value from a function. If no value is returned, the function returns None. The return keyword can also be used to exit a function early.

# Example of arguments and return values

def add(a, b): # a and b are called arguments
    c = a + b
    return c # c is called a return value

Calling a function

To call a function, you use the function name followed by parentheses. The parentheses can contain arguments to pass to the function. The arguments are separated by commas. The order of the arguments matters.

# Example of calling a function

add(1, 2) # returns 3

We can also store the return value of a function in a variable to use later.

# Example of storing the return value of a function in a variable

result = add(1, 2)
print(result) # prints 3

Docstrings

Docstrings are used to document functions. They are defined by a string literal that is the first statement in the function. They are also used by the help() function to display documentation for a function.

# Example of a docstring

def add(a, b):
    """Adds two numbers together"""
    c = a + b
    return c

Type annotations

Type annotations are used to specify the type of arguments and return values. They are defined by a colon followed by the type. They are not enforced by the Python interpreter, but they can be used by other tools (e.g. pydantic).

# Example of type annotations

def add(a: int, b: int) -> int:
    c = a + b
    return c

The example above takes two integers and returns an integer.

Default arguments

Default arguments are used to specify a default value for an argument. If the argument is not passed to the function, the default value is used instead. Default arguments must be defined after all non-default arguments.

# Example of default arguments

def add(a, b, c=0):
    d = a + b + c
    return d

add(1, 2) # returns 3
add(1, 2, 3) # returns 6

Arbitrary arguments (args)

Arbitrary arguments are used to pass a variable number of arguments to a function. They are defined by an asterisk (*) followed by the name of the argument. The arguments are passed to the function as a tuple.

# Example of arbitrary arguments

def add(*args):
    total = 0
    for arg in args:
        total += arg
    return total

add(1, 2, 3) # returns 6

Keyword arguments (kwargs)

Keyword arguments are used to pass a variable number of keyword arguments to a function. They are defined by two asterisks (**) followed by the name of the argument. The arguments are passed to the function as a dictionary.

# Example of keyword arguments

def add(**kwargs):
    total = 0
    for key, value in kwargs.items():
        total += value
    return total

add(a=1, b=2, c=3) # returns 6

Lamda functions

Lambda functions are anonymous functions (no named identifier) that can be used to create a function on the fly. They are useful when you need to pass a function as an argument to another function. They are defined with the lambda keyword followed by the arguments, a colon, and the expression to return.

# Example of a lambda function

# a,b are the arguments, a + b is the expression to return
add = lambda a, b: a + b 

add(1, 2) # returns 3

Lamda functions in pandas

Lamda functions are useful when used with pandas. They can be used to create new columns in a dataframe.

# Example of using a lambda function to create a new column in a dataframe

# Import pandas
import pandas as pd

# Create a dataframe 
df = pd.DataFrame({
    "a": [1, 2, 3],
    "b": [4, 5, 6]
})

# Create a new column with the sum of a and b
df["c"] = df.apply(lambda row: row["a"] + row["b"], axis=1)

Decorator functions

Decorator functions are used to modify the behavior of other functions. They are defined with the @ symbol followed by the name of the decorator function. The decorator function must take a function as an argument and return a function.

# Example of a decorator function

def decorator(func):
    def wrapper(*args, **kwargs):
        print("Before")
        func(*args, **kwargs)
        print("After")
    return wrapper

@decorator
def add(a, b):
    print(a + b)

add(1, 2)

A common use case for decorators is to determine the execution time of a function. Here is an example of a timer:

# Example of a decorator function that times a function

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print(f"Time taken: {end - start}")
    return wrapper

@timer
def add(a, b):
    print(a + b)

add(1, 2)

Recursive functions

Recursive functions are functions that call themselves. They are useful for performing a task multiple times. They are defined with the def keyword followed by the name of the function, the arguments, a colon, and the expression to return. The expression to return must call the function again with different arguments.

# Example of a recursive function

def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n - 1)

factorial(5) # returns 120

I would be careful with these as they can cause infinite loops if not used correctly.

Exercises

You can find some exercises to practice your python skills here and here.