Tuple[Callable, Any, ...]

Posted on Mon, 29 Jan 2018 in Python

Type hints could help you a lot with a big Python project. However, they sometimes require code refactoring. I wrote about it last year in this article, but I have found a good example for this only now.

Look at this code:

def process(workflow_step):
    func = step[0]
    args = step[1:]
    return func(*args)

What can we get from this piece of code? That workflow_step is a sequence witch first element is a Callable object and the other items, if any, are its arguments. Let's assume that workflow_step is a Tuple. The problem is that the type (Tuple) -> Any for this function is utterly uninformative. Can I call process with an empty tuple? Is (1, 2, 3) OK?

(Tuple[Callable, Any, ...]) -> Any is much better. However, it is not valid. Typing library doesn't allow such syntax. For simple cases, one of the options is to use Union[Tuple[Callable], Tuple[Callable, Any]] or something similar. In any other cases there is the only one option: rewrite this piece of code.

There are plenty of options how to do it, for example, using NamedTuple.

class WorkflowStep(NamedTuple):
    callable  # type: Callable
    args  # type: Tuple

 def process(workflow_step):
    # type: (WorkflowStep) -> Any
    return step.callable(args. args)

Maybe this is not the best piece of code you've ever seen. But no doubts it is much more structured and readable than it was before.