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 integerWe 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 + bA 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 errorTyped 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.
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()