3.6. Typing TypedDict¶
Since Python 3.8
PEP 589 -- TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys
PEP 655 –- Marking individual TypedDict items as required or potentially-missing
3.6.1. SetUp¶
>>> from typing import TypedDict
3.6.2. Dict¶
>>> pt: dict = {'x':1 , 'y':2}
>>> pt: dict = {'a':1 , 'b':2}
3.6.3. Dict[...]¶
>>> pt: dict[str, int] = {'x':1 , 'y':2}
>>> pt: dict[str, int] = {'a':1 , 'b':2}
3.6.4. TypedDict¶
Since Python 3.8
PEP 589 -- TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys
>>> class Point(TypedDict):
... x: int
... y: int
>>>
>>> pt = Point(x=1, y=2) # ok
>>> pt = Point(x=1, y=2, z=3) # error, Extra key 'z' for TypedDict 'Point'
>>> pt = Point(x=1, y=2) # error, TypedDict 'Point' has missing keys: 'x', 'y'
3.6.5. Optional Values¶
>>> class Point(TypedDict):
... x: int
... y: int
... z: int | None
>>> Point(x=1, y=2, z=3) # ok
{'x': 1, 'y': 2, 'z': 3}
>>> Point(x=1, y=2, z=None) # ok
{'x': 1, 'y': 2, 'z': None}
>>> Point(x=1, y=2) # error, TypedDict 'Point' has missing key: 'z'
{'x': 1, 'y': 2}
3.6.6. Default Values¶
Does not support default values
>>> class Point(TypedDict):
... x: int
... y: int
... z: int = 0
>>> Point(x=1, y=2, z=3) # ok
{'x': 1, 'y': 2, 'z': 3}
>>> Point(x=1, y=2) # error, TypedDict 'Point' has missing key: 'z'
{'x': 1, 'y': 2}
3.6.7. NotRequired¶
Since Python 3.11
PEP 655 –- Marking individual TypedDict items as required or potentially-missing
>>> from typing import NotRequired
>>> class Point(TypedDict):
... x: int
... y: int
... z: NotRequired[int]
>>> Point(x=1, y=2) # ok
{'x': 1, 'y': 2}
>>> Point(x=1, y=2, z=3) # ok
{'x': 1, 'y': 2, 'z': 3}
3.6.8. Required¶
Since Python 3.11
PEP 655 –- Marking individual TypedDict items as required or potentially-missing
>>> from typing import Required, NotRequired
>>> class Point(TypedDict):
... x: Required[int]
... y: Required[int]
... z: NotRequired[int]
>>> Point(x=1, y=2) # ok
{'x': 1, 'y': 2}
>>> Point(x=1, y=2, z=3) # ok
{'x': 1, 'y': 2, 'z': 3}
3.6.9. Total¶
Since Python 3.11
PEP 655 –- Marking individual TypedDict items as required or potentially-missing
>>> class Point(TypedDict, total=True):
... x: int
... y: int
... z: int
>>> Point(x=1, y=2) # error, TypedDict 'Point' has missing key: 'z'
{'x': 1, 'y': 2}
>>> Point(x=1, y=2, z=3) # ok
{'x': 1, 'y': 2, 'z': 3}
3.6.10. Use Case - 0x01¶
>>> class User(TypedDict):
... firstname: str
... lastname: str
>>> def hello(user: User):
... result = f'Hello {user["firstname"]} {user["lastname"]}'
>>> mark: User = {'firstname': 'Mark', 'lastname': 'Watney', 'age': 40}
>>> hello(mark) # ok
>>> mark: User = {'firstname': 'Mark', 'lastname': 'Watney'}
>>> hello(mark) # error: missing `age`
>>> mark: User = {'firstname': 'Mark'}
>>> hello(mark) # error: missing `lastname` and `age`
>>> mark = User(firstname='Mark', lastname='Watney', age=42)
>>> hello(mark) # ok
>>> mark = User(firstname='Mark', lastname='Watney')
>>> hello(mark) # error: missing `age`
>>> mark = User(firstname='Mark')
>>> hello(mark) # error: missing `lastname`
>>> iris = {'genus': 'Iris', 'species': 'Setosa'}
>>> hello(iris) # error: not an user
3.6.11. Use Case - 0x02¶
>>> from datetime import datetime, date, time
>>> from typing import Literal, TypedDict
>>>
>>> class Log(TypedDict):
... when: datetime
... level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
... message: str
>>>
>>>
>>> def parse(line: str) -> Log:
... d, t, lvl, msg = line.strip().split(', ', maxsplit=3)
... d = date.fromisoformat(d)
... t = time.fromisoformat(t)
... dt = datetime.combine(d,t)
... return Log(when=dt, level=lvl, message=msg)
>>> line = '1969-07-21, 02:56:15, WARNING, Neil Armstrong first words on the Moon'
>>>
>>> parse(line)
{'when': datetime.datetime(1969, 7, 21, 2, 56, 15),
'level': 'WARNING',
'message': 'Neil Armstrong first words on the Moon'}
3.6.12. Further Reading¶
More information in Type Annotations
More information in CI/CD Type Checking
3.6.13. References¶
3.6.14. Assignments¶
"""
* Assignment: Typing Annotations Mapping
* Complexity: easy
* Lines of code: 3 lines
* Time: 2 min
English:
1. Declare proper types for variables
2. Use `TypedDict`
3. Run doctests - all must succeed
Polish:
1. Zadeklaruj odpowiedni typ zmiennych
2. Użyj `TypedDict`
3. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert data == {'firstname': 'Mark', 'lastname': 'Watney', 'age': 40}, \
'Do not modify variable `data` value, just add type annotation'
"""
# Declare proper types for variables
class User:
...
# Do not modify lines below
data: User = {'firstname': 'Mark', 'lastname': 'Watney', 'age': 40}