• Home

On this page

  • Static vs Dynamic Typing
  • Typed annotations
  • Exercise

Types and Type hints

Static vs Dynamic Typing

can be influenced by whether a language is compiled or interpreted.

Python is dynamically typed, while Java is statically typed.

my_var = 10       #  <- this is a string
my_var = "hello"  # <- this is an integer

We can explicitly define the type of a variable using type hints.

my_var: int = 10
my_var: str = "hello"
my_list: list[int] = [1, 2, 3]

But normally we don’t have to as we can directy infer the type from the value.

We can also use type hints to enforce type safety of arguments and return values of functions:

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

A class can also be a type:

class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

person: Person = Person("John", 30)

Union types can be used to allow multiple types for a variable:

my_list: list[int | float] = [1, 2, 3, 3.14]
my_list: list[int | float | str] = [1,2,3, 3.14, "hello"] # <- this is an error

Typed annotations

Looking at this ‘un-typed’ code, we can see several problems: - we do not know what uses, plans, and products are, if we want to know we have to look at the implementation, which could be inconvenient when this function is used in a large codebase/need to be referred to multiple times.

Note

Regardless of what types of programming language you use, use explicit type hints to make the code more readable and maintainable.

def compute_stats(uses, plans, products):
    total_uses = sum(uses)
    total_plans = len(plans)
    total_products = len(products)

    return total_uses, total_plans, total_products


def main() -> None:
    uses = [1, 2, 3]
    plans = ["plan1", "plan2", "plan3"]
    products = ["product1", "product2", "product3"]

    total_uses, total_plans, total_products = compute_stats(uses, plans, products)

    print(f"Total uses: {total_uses}")
    print(f"Total plans: {total_plans}")
    print(f"Total products: {total_products}")

if __name__ == "__main__":
    main()

Typed annotations help you: - improve the readability of the code - catch error early and more easily in the development process - thinking about the types of the variables might also get you to think about the general design of the code and the data flow.

Exercise

Add type hints to the following functions. Make sure that no red squiggles appear in your IDE with your type checker set to “strict”. Make sure that you have installed pylance or similar to get type hints in your IDE.

def add_book(collection, title, author):
    collection.append({"title": title, "author": author})

def display_books(collection):
    for book in collection:
        print(f"Title: {book['title']}, Author: {book['author']}")

def find_book_by_title(collection, title):
    for book in collection:
        if book['title'] == title:
            return book
    return None

def filter_even_numbers(numbers):
    return [num for num in numbers if num % 2 == 0]

def main():
    my_books = []
    add_book(my_books, "1984", "George Orwell")
    add_book(my_books, "To Kill a Mockingbird", "Harper Lee")
    display_books(my_books)

if __name__ == "__main__":
    main()
class ShoppingCart:
    def __init__(self, owner):
        """
        Initializes a shopping cart.

        Args:
            owner (str): The owner of the shopping cart.
        """
        self.owner = owner
        self.items = []

    def add_item(self, id, quantity, price):
        """
        Adds an item to the shopping cart.

        Args:
            id (int): The name of the item.
            quantity (int): The quantity of the item.
            price (float): The price per unit of the item.
        """
        item = {"id": id, "quantity": quantity, "price": price}
        self.items.append(item)

    def calculate_total(self):
        """
        Calculates the total cost of items in the shopping cart.

        Returns:
            float: The total cost.
        """
        total_cost = sum(item["quantity"] * item["price"] for item in self.items)
        return total_cost

    def filter_items(self, filter_func):
        """
        Filters the items in the shopping cart.

        Args:
            filter_func (function): The function used to filter the items.
        """

        filtered_items = [item for item in self.items if filter_func(item)]
        return filtered_items


def main() -> None:
    alice_cart = ShoppingCart("Alice")

    alice_cart.add_item(1, 3, 1.50)
    alice_cart.add_item(2, 2, 0.75)
    alice_cart.add_item(3, 1, 15.99)

    total_cost_alice = alice_cart.calculate_total()
    print(total_cost_alice)


if __name__ == "__main__":
    main()