I am new to using type checking with python, and want to create a function that takes a single value, and either returns None if that value is None, or returns the result of applying a function to it. It works, but doesn't type check when passing a type as a function, such as int.
1st attempt:
from typing import Callable, Optional, TypeVar, Union
A = TypeVar('A')
B = TypeVar('B')
def maybe(val: A, fn: Callable[[A], B]) -> Optional[B]:
if val is not None:
return fn(val)
return None
myVar: Optional[Union[str, int]] = "42"
ret = maybe(myVar, int)
That appeared to work fine and type check OK when I called maybe(myVar, myFn) and myFn was a normal function or lambda. However, if I try maybe(myVar, int), then mypy complains that int has the wrong type:
test.py:12: error: Argument 2 to "maybe" has incompatible type "Type[int]"; expected "Callable[[Union[str, int, None]], int]"
Although the documentation describes int() as a built-in function, it actually has the type <class 'type'>, so the error kind of makes sense. However, although the error is raised about the second argument (int), mypy only complains when the first argument is Optional. If myVar is a plain str or int, it type checks OK.
2nd attempt
I tried changing the function signature to accept types as well as callables:
from typing import Callable, Optional, Type, TypeVar, Union
A = TypeVar('A')
B = TypeVar('B')
def maybe(val: A, fn: Union[Callable[[A], B], Type[B]]) -> Optional[B]:
if val is not None:
return fn(val)
return None
myVar: Optional[Union[str, int]] = "42"
ret = maybe(myVar, int)
That fixed the errors when calling maybe(). Instead, at the line return fn(val), mypy gives an error I don't understand:
test.py:8: error: Too many arguments for "object"
How can I fix this error? Is there a more pythonic way of doing what I want?
Versions
Python 3.7.7
mypy 0.770