Is it possible to define that a class needs a specific constructor?
class Constructible(Protocol):
def __init__(self, i: int): # how do I do this?
raise NotImplementedError
def get_value(self):
raise NotImplementedError
def map_is(cs: Iterable[Constructible], i: int):
mapped = tuple(C(i) for C in cs)
values = tuple(c.get_value() for c in mapped)
# both the constructor and a member method are used
return mapped, values
# implementors (omitting __hash__ and __eq__ for brevity)
class X(Constructible):
def __init__(self, i):
self.i=i
def get_value(self):
return self.i
class Sq(Constructible):
def __init__(self, i):
self.i=i
def get_value(self):
return self.i * self.i
cs, values = tuple(map_is((X, Sq), 5))
assert values == (5, 25)
When specifying it like this, I get
$ mypy constr.py
constr.py:12: error: "Constructible" not callable
Found 1 error in 1 file (checked 1 source file)
Is this even possible? Or should I revert to a factory function @classmethod def construct(i: int): Self
?
As explained by @jonrsharpe, you do not pass an iterable of Constructible
instances to map_is
but an iterable of classes. That means that you should define the function that way:
def map_is(cs: Iterable[Type[Constructible]], i: int):
return (C(i) for C in cs)
That is enough for mypy to validate the code.
But there is an unrelated problem: you never declared any __hash__
nor __equal__
special method. That means that in assert values == (X(5), Sq(5))
the equality used is the one defined on the object
class (same as is
). So after the above fix, the code executes successfully but still raises an AssertionError
, because the objects do have same value, yet they are distinct objects...