So, what you are describing is structural typing. This is distinct from the class-based nominal subtyping that the python typing system is based on. However, structural subtyping is sort of the statically typed version of Python's dynamic duck typing.
Python's typing system allows a form of this through typing.Protocol
.
An example, suppose we have a Python module, test_typing.py
:
from typing import Protocol
from dataclasses import dataclass
class Named(Protocol):
name: str
@dataclass
class A:
name: str
id: int
@dataclass
class B:
name: int
@dataclass
class C:
foo: str
def frobnicate(obj: Named) -> int:
return sum(map(ord, obj.name))
frobnicate(A('Juan', 1))
frobnicate(B(8))
frobnicate(C('Jon'))
Using mypy version 0.790:
(py38) juanarrivillaga@Juan-Arrivillaga-MacBook-Pro ~ % mypy test_typing.py
test_typing.py:28: error: Argument 1 to "frobnicate" has incompatible type "B"; expected "Named"
test_typing.py:28: note: Following member(s) of "B" have conflicts:
test_typing.py:28: note: name: expected "str", got "int"
test_typing.py:29: error: Argument 1 to "frobnicate" has incompatible type "C"; expected "Named"
Found 2 errors in 1 file (checked 1 source file)