4. Type Annotation Classes
By Bernd Klein. Last modified: 13 Jul 2023.
This chapter of our Python course is about annotating classes. So you will nt learn the thoery of Python classes and how to write proper Python classes. If you want to learn all about object oriented programming in Python, we recommend our course on OOP:
We saw in the following Python example a class with type annotations:
%%writefile example.py
class Rectangle:
def __init__(self, length: float, width: float) -> None:
self.length: float = length
self.width: float = width
def area(self) -> float:
return self.length * self.width
def perimeter(self) -> float:
return 2 * (self.length + self.width)
r: Rectangle
r = Rectangle(5.0, 3.0)
print(r.area())
print(r.perimeter())
OUTPUT:
Overwriting example.py
!python example.py
OUTPUT:
15.0 16.0
!mypy example.py
OUTPUT:
Success: no issues found in 1 source file
Another Example
%%writefile example.py
from typing import List
class ShoppingCart:
def __init__(self, items: List[str]) -> None:
self.items: List[str] = items
def add_item(self, item: str) -> None:
self.items.append(item)
def remove_item(self, item: str) -> None:
self.items.remove(item)
def get_items(self) -> List[str]:
return self.items
cart: ShoppingCart = ShoppingCart(['cheese'])
print(cart.get_items())
item: str
for item in ['tea', 'coffee']:
cart.add_item(item)
print(cart.get_items())
cart.remove_item('tea')
print(cart.get_items())
OUTPUT:
Overwriting example.py
!python example.py
OUTPUT:
['cheese'] ['cheese', 'tea', 'coffee'] ['cheese', 'coffee']
!mypy example.py
OUTPUT:
Success: no issues found in 1 source file
Live Python training
Enjoying this page? We offer live Python training courses covering the content of this site.
Another Example
%%writefile example.py
from typing import Set
class Person:
def __init__(self, name: str, age: int, hobbies: Set[str]) -> None:
self.name: str = name
self.age: int = age
self.hobbies: Set[str] = hobbies
def add_hobby(self, hobby: str) -> None:
self.hobbies.add(hobby)
def remove_hobby(self, hobby: str) -> None:
if hobby in self.hobbies:
self.hobbies.remove(hobby)
def get_hobbies(self) -> Set[str]:
return self.hobbies
person: Person = Person("Andrea", 25, {"Reading", "Music"})
print(person.get_hobbies())
person.add_hobby("Cooking")
print(person.get_hobbies())
person.remove_hobby("Gardening")
print(person.get_hobbies())
person.remove_hobby("Cooking")
print(person.get_hobbies())
OUTPUT:
Overwriting example.py
!python example.py
OUTPUT:
{'Music', 'Reading'} {'Music', 'Cooking', 'Reading'} {'Music', 'Cooking', 'Reading'} {'Music', 'Reading'}
!mypy example.py
OUTPUT:
Success: no issues found in 1 source file
Yet Another Example
%%writefile example.py
from typing import Set
class Robot:
city: str = "Hamburg"
__forbidden_names: Set[str] = {'Henry', 'Edgar'}
def __init__(self, name: str = 'Marvin') -> None:
self.__name: str
self.name = name
@property
def name(self) -> str:
return self.__name
@name.setter
def name(self, name: str) -> None:
if name in Robot.__forbidden_names:
raise NameError("Not a Valid Robot Name")
else:
self.__name = name
def say_hi(self) -> None:
print(f"HI, I am {self.name} from {self.city}")
x: Robot = Robot("Petra")
print(x.name)
y: Robot = Robot("John")
OUTPUT:
Overwriting example.py
!python example.py
OUTPUT:
Petra
!mypy example.py
OUTPUT:
Success: no issues found in 1 source file
Live Python training
Enjoying this page? We offer live Python training courses covering the content of this site.
Examples with Generic
In this example, the Box class is defined as a generic class using Generic[T]
. The type parameter T
represents the type of the item stored in the box.
The class has an __init__
method that takes an initial item of type T
and assigns it to the item attribute.
The get_item method returns the item stored in the box, which has a return type annotation of T
.
The set_item
method takes a new item of type T
and updates the item attribute accordingly.
%%writefile boxes.py
from typing import TypeVar, Generic
T = TypeVar('T')
class Box(Generic[T]):
def __init__(self, item: T) -> None:
self.item = item
def get_item(self) -> T:
return self.item
def set_item(self, new_item: T) -> None:
self.item = new_item
OUTPUT:
Overwriting boxes.py
You can create instances of the Box class with different types, depending on what type you want the item to be. Here's an example usage:
%%writefile example.py
from boxes import Box
box1: Box[int] = Box[int](42)
print(box1.get_item()) # Output: 42
box2: Box[str] = Box[str]("Hello")
print(box2.get_item()) # Output: Hello
box3: Box[float] = Box[float](3.14)
print(box3.get_item()) # Output: 3.14
#reveal_type(box1)
#reveal_type(box2)
OUTPUT:
Overwriting example.py
!python example.py
OUTPUT:
42 Hello 3.14
!mypy example.py
OUTPUT:
Success: no issues found in 1 source file
The LoggedVar
class is designed to add logging capabilities to a variable, allowing you to track changes and accesses to its value. It serves as a wrapper around a variable, providing methods to set and retrieve its value while logging relevant information.
The class is useful in scenarios where you want to monitor and log the modifications or accesses to a variable, providing insights into its behavior, changes over time, or for debugging and troubleshooting purposes.
%%writefile example.py
from typing import TypeVar, Generic
import logging
T = TypeVar('T')
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: logging.Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
# Example usage
debug_var = LoggedVar[str]('initial', 'debug_var', logging.getLogger('debugging'))
debug_var.set('updated') # Logs: debug_var: Set 'initial'
print(debug_var.get()) # Logs: debug_var: Get 'updated'
debug_var.get()
x = LoggedVar[int](42, 'x', logging.getLogger('debugging'))
x.get()
x.set(42+5)
x.get()
OUTPUT:
Overwriting example.py
!python example.py
OUTPUT:
updated
!mypy example.py
OUTPUT:
Success: no issues found in 1 source file
Live Python training
Enjoying this page? We offer live Python training courses covering the content of this site.