Skip to content

Commit f64b1e1

Browse files
committed
python typing: add absctract abc.ABC vs typing.Protocal and overload
1 parent 605c18d commit f64b1e1

File tree

1 file changed

+65
-2
lines changed

1 file changed

+65
-2
lines changed

docs/posts/2025/2025-02-01-python-type-hints.md

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ categories:
77
comments: true
88
date:
99
created: 2025-02-01
10-
updated: 2025-07-09
10+
updated: 2025-08-17
1111
---
1212

1313
# Python Type Hints
@@ -353,6 +353,33 @@ class Child(Base):
353353
return f"<Child(id={self.id}, name='{self.name}', parent_id={self.parent_id})>"
354354
```
355355

356+
## abstract abc.ABC vs typing.Protocol
357+
358+
`abc.ABC` enforce the inheritance of abstract methods, requiring subclasses to implement them.
359+
`typing.Protocol` is only for typing, allowing for structural subtyping without enforcing inheritance.
360+
361+
```python title="typing.Protocol"
362+
from typing import Protocol
363+
364+
class Shape(Protocol):
365+
def area(self) -> float: ...
366+
367+
# no class Circle(Shape) here
368+
class Circle:
369+
def __init__(self, r: float) -> None:
370+
self.r = r
371+
372+
def area(self) -> float:
373+
return 3.14159 * self.r * self.r
374+
375+
def print_area(s: Shape) -> None:
376+
print(s.area())
377+
378+
c = Circle(10)
379+
# as c has area() method, it matches Shape protocol, MyPy is happy with that.
380+
print_area(c) # ✅ Circle matches Shape structurally
381+
```
382+
356383
## Callable and Protocol
357384

358385
[From MyPy](https://mypy.readthedocs.io/en/stable/protocols.html#callback-protocols): We can use [Protocols](https://typing.python.org/en/latest/spec/protocol.html) to define [callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable) types with a special [**call**](https://docs.python.org/3/reference/datamodel.html#object.__call__) member:
@@ -545,11 +572,47 @@ concat(1, 2) # Error!
545572

546573
## Overloading
547574

548-
Use [@overload](https://mypy.readthedocs.io/en/stable/more_types.html#function-overloading) to let type checkers know that a function can accept different types of arguments and return different types based on those arguments.
575+
Use [@overload](https://mypy.readthedocs.io/en/stable/more_types.html#function-overloading) to let type checkers know that a function can accept different types of arguments and return different types based on those arguments.
549576

550577
!!! note "If there are multiple equally good matching variants (overloaded functions), mypy will select the variant that was defined first."
551578
Put always the finest overloaded function at first: https://mypy.readthedocs.io/en/stable/more_types.html#type-checking-the-variants
552579

580+
### Overloading example
581+
582+
```python title="Overloading __getitem__() method with Python 3.12 syntax"
583+
# https://mypy.readthedocs.io/en/stable/more_types.html#function-overloading
584+
from collections.abc import Sequence
585+
from typing import overload
586+
587+
class MyList[T](Sequence[T]):
588+
@overload
589+
# replace default value (True) of flag in overload definitions
590+
# with ... as a placeholder
591+
def __getitem__(self, index: int, flag: bool = ...) -> T:
592+
"""
593+
The variant bodies must all be empty with ellipsis (`...`),
594+
`pass` keyword is OK too by not recommended.
595+
only the implementation is allowed to contain code.
596+
This is because at runtime, the variants are completely ignored:
597+
they're overridden by the final implementation function.
598+
"""
599+
...
600+
601+
602+
@overload
603+
# replace default value (True) of flag in overload definitions
604+
# with ... as a placeholder
605+
def __getitem__(self, index: slice, flag: bool = ...) -> Sequence[T]: ...
606+
607+
def __getitem__(self, index: int | slice, flag: bool = True) -> T | Sequence[T]:
608+
if isinstance(index, int):
609+
# Return a T here
610+
elif isinstance(index, slice):
611+
# Return a sequence of Ts here
612+
else:
613+
raise TypeError(...)
614+
```
615+
553616
## Typing tools
554617

555618
### MyPy

0 commit comments

Comments
 (0)