The Pythonic way to deal with that would be to just remember that Python is a dynamic language:
def area(shape):
if isinstance(shape, Circle):
...
if isinstance(shape, Square):
...
Or, if you want better coverage from your type checker, from typing import overload
@overload
def area(shape: Circle): ...
@overload
def area(shape: Square): ...
def area(shape):
if isinstance(shape, Circle):
...
if isinstance(shape, Square):
...
This still isn't real overloading. The last one is the one and only function. All the other two bits do is tell the static type checker what kinds of arguments it's prepared to support.edit: Scratch that, I think what I'd really go for in a simpler case like this would just be
def area(shape: Union[Circle, Square]):
...