Reputation: 187
How i can to test that a parameters of function have the same concrete type?
Example:
class A(Generic[T]):
def __init__(p: T):
self._p = p
def get_data(self) -> T:
return self._p
class B(Generic[T]):
def __init__(p: T):
self._p = p
def inc(v: A[T]):
self._p = self._p + v.get_data()
class I(Generic[T]):
def __init__(a: A[T], b: B[T]):
self._a = a
self._b = b
def execute():
self._b.inc(a)
Ok:
I(A(1), B(2)).execute()
Failed:
I(A(1), B("2")).execute()
Upvotes: 0
Views: 3271
Reputation: 3072
So to me it looks like you want to use type variables / generics? That is, when a function is called, that type variable is then bound for that particular call.
For example, we could have a function head()
which optionally returns a head item of a homogenous list (Python doesn't have this restriction for lists, but for now imagine we want to have):
from typing import TypeVar, Optional, List
T = TypeVar("T", int, float, str)
def head(lst: List[T]) -> Optional[T]:
if lst:
return lst[0]
return None
print(head([1, 2]))
print(head(["koi"]))
print(head([]))
Now, any of str, float or int are allowed types for these lists, but they must be homogenous. So the type signature basically says that "head takes list of strings, ints or floats, and whatever the type of the items is in the list, the return value (if present) will be of that type too"
Note that this is quite different from union types, eg. you could have
T = Union[str, float, int]
def head(lst: List[T]) -> Optional[T]:
...
but it wouldn't then work like you want; according to types, returning an int would still be ok even if list contained only strings.
Update: as kindly mentioned by @MisterMiyagi in the comment below, this still requires user to be aware of types that are allowed.
For your use case (with classes), this should be fine (trying to use minimal example):
from typing import TypeVar, Generic
T = TypeVar("T")
class A(Generic[T]):
def a(self, a: T, b: T) -> T:
return a
print(A[int]().a(1, 2))
print(A[float]().a(32.1, 2))
print(A[str]().a("koi", "bar"))
# print(A[int]().a(1, "bar")) -- does not pass type checker
Crucial difference here is that you still need to pass types when you actually call them, but they don't need to be present when you define your generic class.
Check out https://mypy.readthedocs.io/en/stable/generics.html for more information on those.
Upvotes: 1