Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python type hint for Callable with variable number of str/same type arguments?

How can I specify one type for all of these callables:

a(str)
b(str, str)
c(str, str, str)
d(str, str, str, str

I found that I can specify Callable[..., None] in general way but how to specify with details that all arguments will be str without doing ugly syntax Union[Callable[[str], None], Callable[[str, str], None, __more_like_this__]. Is it other method to do it? Can I do it with use typing?

like image 726
Chameleon Avatar asked Aug 26 '19 13:08

Chameleon


2 Answers

You could use a callback protocol to specify a function type with variadic string arguments:

from typing_extensions import Protocol


class Callback(Protocol):
    def __call__(self, *args: str) -> None: ...

And use it like this:

def handler(cb: Callback) -> None:
    cb('a', 'b', 'c')

def callback(*args: str) -> None:
    pass

handler(callback)

Note that the callback has to take variadic arguments, eg. this won't work:

def callback(a: str, b: str) -> None:
    pass

Protocols were added in Python 3.8 to the standard library typing module, so if you want to use them on Python 3.5-3.7, you will need to install the typing-extensions module from PyPI.

like image 95
Agost Biro Avatar answered Sep 20 '22 16:09

Agost Biro


What you want is the union of 4 distinct types.

t1 = Union[
 Callable[[str],Any],
 Callable[[str,str],Any],
 Callable[[str,str,str],Any],
 Callable[[str,str,str,str],Any],
]

Constrast that with the type of function that can accept 1 to 4 arguments:

t2 = Callable[[str,Optional[str],Optional[str],Optional[str]],Any]

A function like

def foo(x: str, y:str):

does not belong to the second type above. If I say I need a function of type t2, you don't know how many arguments I might try to pass. I could give you foo, but then you might try to pass 3 arguments, or only 1, and get a TypeError.

If you ask for a function of type t1, it's OK for me to give you foo. t1 does not promise that all values in t1 can more or less than exactly 3 arguments; it only includes values that do.

like image 39
chepner Avatar answered Sep 20 '22 16:09

chepner