18.10. Typing Type
All classes are types
>>> class Account:
... firstname: str
... lastname: str
...
... def __init__(self, firstname: str, lastname: str) -> None:
... self.firstname = firstname
... self.lastname = lastname
...
... def login(self, username: str, password: str | None = None) -> None:
... ...
...
... def logout(self) -> None:
... ...
>>>
>>>
>>> class User(Account):
... pass
>>>
>>> class Admin(Account):
... pass
>>>
>>>
>>> a: Account = User('Alice', 'Apricot')
>>> b: Account = Admin('Bob', 'Blackthorn')
18.10.1. Instance
>>> class User:
... pass
>>>
>>>
>>> a: User = User()
>>> b: User = User()
18.10.2. Inheritance
Dependency Inversion Principle
Always depend upon abstraction not an implementation
More information in OOP SOLID
>>> class Account:
... pass
>>>
>>> class User(Account):
... pass
>>>
>>> class Admin(Account):
... pass
>>>
>>>
>>> a: Account = User()
>>> b: Account = Admin()
18.10.3. Instance Variables
>>> class User:
... firstname: str
... lastname: str
>>>
>>>
>>> a = User()
>>> a.firstname = 'Alice'
>>> a.lastname = 'Apricot'
18.10.4. Class Variables
ClassVar indicates that a given attribute is intended to be used as a class variable and should not be set on instances of that class.
https://docs.python.org/3/library/typing.html#typing.ClassVar
>>> from typing import ClassVar
>>>
>>> class User:
... AGE_MIN: ClassVar[int] = 0
... AGE_MAX: ClassVar[int] = 130
18.10.5. Method Return Type
>>> class User:
... def login(self) -> None:
... ...
18.10.6. Required Method Arguments
>>> class User:
... def login(self, username: str, password: str):
... ...
18.10.7. Optional Method Arguments
>>> class User:
... def login(self, username: str, password: str | None = None):
... ...
18.10.8. Init Method
>>> class User:
... firstname: str
... lastname: str
...
... def __init__(self, firstname: str, lastname: str) -> None:
... self.firstname = firstname
... self.lastname = lastname
18.10.9. Recap
Type annotations
Type hints
Optional, but a good practice
Python does not verify if values have correct types
IDEs such as PyCharm, VS Code or tools such as
mypycan do that
No Attribute Definition:
>>> class User:
... pass
Basic Types:
>>> class User:
... firstname: str
... lastname: str
... age: int
Union:
>>> class User:
... firstname: str
... lastname: str
... age: int | float
Optional:
>>> class User:
... firstname: str
... lastname: str
... age: int | float
... height: float | None
... weight: float | None
Sequences:
>>> class User:
... firstname: str
... lastname: str
... age: int
... groups: list[str]
Relation One to One:
>>> class Group:
... gid: int
... name: int
>>>
>>>
>>> class User:
... firstname: str
... lastname: str
... group: Group
Relation One to Many:
>>> class Group:
... gid: int
... name: str
>>>
>>>
>>> class User:
... firstname: str
... lastname: str
... groups: list[Group]
18.10.10. Use Case - 1
>>> class Point:
... x: int
... y: int
... z: int
18.10.11. Use Case - 2
>>> class Date:
... year: int
... month: int
... day: int
18.10.12. Use Case - 3
>>> class Laptop:
... cpu: str
... ram: str
... ssd: str
18.10.13. Use Case - 4
>>> class Iris:
... features: list[float]
... label: str
18.10.14. Use Case - 5
>>> class Iris:
... sepal_length: float
... sepal_width: float
... petal_length: float
... petal_width: float
... species: str
18.10.15. Use Case - 6
>>> class User:
... firstname: str
... lastname: str
... email: str
... active: bool
... age: int | float
... height: float | None
... weight: float | None
... groups: list[str] | None
... friends: list['User'] | None
18.10.16. Use Case - 7
>>> from datetime import date
>>> from typing import Literal
>>>
>>>
>>> class Address:
... type: Literal['home', 'work']
... street: str
... house: str
... apartment: str
... postcode: str
... city: str
... region: str
... country: str
>>>
>>>
>>> class PhoneNumber:
... type: Literal['home', 'work', 'mobile']
... number: str
>>>
>>>
>>> class User:
... firstname: str
... lastname: str
... age: int | float
... birthdate: date
... gender: Literal['male', 'female']
... height: float | None
... weight: float | None
... education: list[str] | None
... job: str | None
... addresses: list[Address] | None
... emails: list[str] | None
... phones: PhoneNumber | None
... friends: list['Person'] | None
18.10.17. Use Case - 8
>>> class Point:
... x: int
... y: int
...
... def set_coordinates(self, x: int, y: int) -> None:
... self.x = x
... self.y = y
...
... def get_coordinates(self) -> tuple[int,int]:
... return self.x, self.y
18.10.18. Use Case - 9
>>> class Point:
... x: int
... y: int
...
... def __init__(self, x: int = 0, y: int = 0) -> None:
... self.x = x
... self.y = y
>>>
>>>
>>> class Position:
... position: Point
...
... def __init__(self, initial_position: Point = Point()) -> None:
... self.position = initial_position
...
... def get_coordinates(self) -> Point:
... return self.position
18.10.19. Use Case - 10
SOLID Dependency Inversion Principle
>>> class Cache:
... pass
>>>
>>> class DatabaseCache(Cache):
... pass
>>>
>>> class MemoryCache(Cache):
... pass
>>>
>>> class FilesystemCache(Cache):
... pass
>>>
>>>
>>> a: Cache = DatabaseCache()
>>> b: Cache = MemoryCache()
>>> c: Cache = FilesystemCache()
18.10.20. Use Case - 11
>>> class Iris:
... def __init__(self, features: list[float], label: str) -> None:
... self.features: list[float] = features
... self.label: str = label
>>>
>>> data: list[Iris] = [
... Iris([4.7, 3.2, 1.3, 0.2], 'setosa'),
... Iris([7.0, 3.2, 4.7, 1.4], 'versicolor'),
... Iris([7.6, 3.0, 6.6, 2.1], 'virginica'),
... ]
18.10.21. Use Case - 12
>>> from typing import ClassVar
>>>
>>> class Settings:
... RESOLUTION_X_MIN: ClassVar[int] = 0
... RESOLUTION_X_MAX: ClassVar[int] = 1024
... RESOLUTION_Y_MIN: ClassVar[int] = 0
... RESOLUTION_Y_MAX: ClassVar[int] = 768
18.10.22. Use Case - 13
>>> from typing import ClassVar
>>>
>>>
>>> class Position:
... x: int
... y: int
>>>
>>>
>>> class Hero:
... HEALTH_MIN: ClassVar[int] = 50
... HEALTH_MAX: ClassVar[int] = 100
... GOLD_MIN: ClassVar[int] = 50
... GOLD_MAX: ClassVar[int] = 100
... DAMAGE_MIN: ClassVar[int] = 5
... DAMAGE_MAX: ClassVar[int] = 20
... name: str
... health: int
... gold: int
... position: Position
18.10.23. Use Case - 14
>>> from uuid import uuid4
>>> from typing import Final
>>>
>>>
>>> class User:
... firstname: str
... lastname: str
... uuid: Final[uuid4]
...
... def __init__(self, firstname: str, lastname: str, age: int) -> None:
... self.firstname = firstname
... self.lastname = lastname
... self.uuid = uuid4()
18.10.24. Use Case - 15
>>> from typing import overload
>>>
>>>
>>> class User:
... @overload
... def login(self, username: str, password: str) -> None:
... ...
...
... @overload
... def login(self, username: str, passkey: bytes) -> None:
... ...