У меня есть следующая функция:
#!/usr/bin/env python3
from typing import Union
def foo(b: Union[str, int]) -> int:
def bar(a: int = b) -> int: # Incompatible default for argument "a" (default has type "Union[str, int]", argument has type "int")
return a + 1
if isinstance(b, str):
return bar(0)
else:
return bar()
print(foo(3)) # 4
print(foo("hello")) # 1
В строке, где я определяю bar
, Mypy говорит, что настройка b
по умолчанию не будет работать.
Однако из-за того, как работает программа, единственный способ использовать значение по умолчанию b
- это если b
является целым числом. Так что это должно работать нормально.
Но Мипи этого не понимает.
Как я могу
- Получите Mypy, чтобы понять, что
int
является правильным типом для a
или
- Исправьте это некоторым способом, который не вызывает слишком много дублирования кода.
(Например, я знаю, что мог бы написать две foo
функции с разными сигнатурами, но это было бы слишком много дублирования кода.)
TL; DR ниже - это только мой реальный пример использования, поскольку по крайней мере один ответ основывался на том, насколько простым был мой MCVE выше.
Это функция, которая принимает словарь. Функция возвращает декоратор, который при использовании добавит декорированную функцию (декорированная функция - TypeChecker
) к словарю. Декоратор допускает параметр, который указывает имя / ключ, под которым декорированная функция (TypeChecker
) находится в словаре. Если имя не указано, оно будет использовать другую функцию (StringHelper.str_function
) для определения имени по свойствам самой функции.
Из-за того, как работают параметры декоратора, создатель декоратора должен принимать либо имя (или ничего), либо функцию. Если для этого требуется только функция, то имя не указано, и оно должно получить имя из функции. Если оно принимает только имя, оно будет вызвано снова в функции, и имя должно быть использовано. Если для этого ничего не требуется, то он снова будет вызван в функции и должен получить имя из функции.
def get_type_checker_decorator(type_checkers: Dict[str, TypeChecker]) -> Callable[[Union[Optional[str], TypeChecker]], Union[Callable[[TypeChecker], TypeChecker], TypeChecker]]:
@overload
def type_checker_decorator(name: Optional[str]) -> Callable[[TypeChecker], TypeChecker]:
pass
@overload
def type_checker_decorator(name: TypeChecker) -> TypeChecker:
pass
def type_checker_decorator(name: Union[Optional[str], TypeChecker] = None) -> Union[Callable[[TypeChecker], TypeChecker], TypeChecker]:
# if name is a function, then the default will never be used
def inner_decorator(function: TypeChecker, name: Optional[str] = name) -> TypeChecker: # this gives the Mypy error
if name is None:
name = StringHelper.str_function(function)
type_checkers[name] = function
def wrapper(string: str) -> bool:
return function(string)
return wrapper
if callable(name):
# they just gave us the function right away without a name
function = name
name = None
return inner_decorator(function, name)
else:
assert isinstance(name, str) or name is None
# should be called with just the function as a parameter
# the name will default to the given name (which may be None)
return inner_decorator
return type_checker_decorator