I have a ValuePropagator
:
V = TypeVar("V")
class ValuePropagator(ABC, Generic[V]):
@abstractmethod
def get(self, funcs: Sequence[Callable[[V], V]], value: V) -> V:
pass
A sample implementation propagates value
eagerly, calling all of funcs
on each invocation of get
:
class EagerValuePropagator(ValuePropagator[V], Generic[V]):
def get(self, funcs: Sequence[Callable[[V], V]], value: V) -> V:
for func in funcs:
value = func(value)
return value
I also have other implementations that do various levels of caching. One caches the final value after applying all funcs
, the other caches intermediate value after applying each func
. All is good so far.
My new use case requires intermediate types to be different than V
. For example, I may receive 2 funcs
: a Callable[[V1], V2]
and Callable[[V2], V3]
. My get
method would then need to return V3
, given a V1
.
My first effort was to compose these funcs
beforehand into one Callable[[V1], V3]
. But many implementations of ValuePropagator
require access to the separated funcs
for caching strategies, and passing a composed Callable
would take away this granularity.
How can I change ValuePropagator
to support multiple types between these funcs
, while keeping type safety? Couple specifications:
Passing
Callable[[V1], V2]
andCallable[[V1], V3]
would need to fail type checking because the output of the first callable is of a different type than the input of the second, causing the piping to fail.I need to be able to receive all the functions up front such that parts of my cumulative operation can remain cached, while others remain uncached.
As a last resort, I can keep this logic untyped using Any
, but would appreciate any ideas to try beforehand.