Python 如何让Mypy意识到默认值赢了';在某些情况下不能使用

Python 如何让Mypy意识到默认值赢了';在某些情况下不能使用,python,python-3.x,typing,mypy,default-parameters,Python,Python 3.x,Typing,Mypy,Default Parameters,我有以下功能: #/usr/bin/env蟒蛇3 从键入导入联合 def foo(b:Union[str,int])->int: def bar(a:int=b)->int:#参数“a”的默认值不兼容(默认值的类型为“Union[str,int]”,参数的类型为“int”) 返回a+1 如果存在(b,str): 返回条(0) 其他: 返回条() 印刷品(foo(3))#4 打印(foo(“你好”)#1 在我定义bar的那一行,Mypy说将b设置为默认值将不起作用 但是,由于程序的工作方式,使用

我有以下功能:

#/usr/bin/env蟒蛇3
从键入导入联合
def foo(b:Union[str,int])->int:
def bar(a:int=b)->int:#参数“a”的默认值不兼容(默认值的类型为“Union[str,int]”,参数的类型为“int”)
返回a+1
如果存在(b,str):
返回条(0)
其他:
返回条()
印刷品(foo(3))#4
打印(foo(“你好”)#1
在我定义
bar
的那一行,Mypy说将
b
设置为默认值将不起作用

但是,由于程序的工作方式,使用默认值
b
的唯一方法是
b
为整数。所以这应该很好

但是Mypy没有意识到这一点

我怎么能

  • 让Mypy意识到
    int
    a
  • 这是一种不会导致太多代码重复的方法
  • (例如,我知道我可以用不同的签名编写两个
    foo
    函数,但这会造成太多的代码重复。)

    TL;下面的DR只是我的实际用例,因为至少有一个答案取决于我上面的MCVE有多简单。

    这是一个需要字典的函数。该函数返回一个decorator,当使用该decorator时,该decorator将把修饰函数(修饰函数是
    类型检查器
    )添加到字典中。decorator允许使用一个参数,该参数指定修饰函数(
    TypeChecker
    )在字典中所处的名称/键。如果未指定名称,则它将使用不同的函数(
    StringHelper.str_function
    )从函数本身的属性中找出名称

    由于decorator参数的工作方式,decorator创建者需要接受名称(或不接受名称)或函数。如果它只接受函数,那么没有指定名称,它应该从函数中获取一个名称。如果它只使用名称,那么它将在函数上再次调用,并且应该使用名称。如果它不接受任何内容,那么它将在函数上再次调用,并且它应该从函数中获取一个名称

    def get_type_checker_decorator(type_checker:Dict[str,TypeChecker])->可调用[[Union[Optional[str],TypeChecker]],联合[Callable[[TypeChecker],TypeChecker],TypeChecker]]:
    @超载
    def type_checker_decorator(名称:可选[str])->可调用[[TypeChecker],TypeChecker]:
    通过
    @超载
    def type_checker_decorator(名称:TypeChecker)->TypeChecker:
    通过
    def type_checker_decorator(名称:Union[Optional[str],TypeChecker]=None)->Union[Callable[[TypeChecker],TypeChecker],TypeChecker]:
    #如果name是一个函数,那么将永远不会使用默认值
    def internal_decorator(函数:TypeChecker,名称:可选[str]=name)->TypeChecker:#这会给出Mypy错误
    如果名称为“无”:
    name=StringHelper.str_函数(函数)
    类型\u checkers[名称]=函数
    def包装器(字符串:str)->bool:
    返回函数(字符串)
    返回包装器
    如果可调用(名称):
    #他们只是给了我们一个没有名字的功能
    函数=名称
    name=None
    返回内部修饰符(函数、名称)
    其他:
    断言isinstance(name,str)或name为None
    #应仅使用函数作为参数调用
    #该名称将默认为给定名称(可能为无)
    返回内部装饰器
    返回类型\u checker\u decorator
    
    在写这个问题时,我想我自己已经回答了,所以我不妨与大家分享一下

    这个解决方案有点尴尬,但这是我所能想到的最好的解决方案,而且似乎有效。首先,键入
    a
    作为整数或字符串。然后,作为函数的第一行,断言
    a
    int

    在一起,看起来像

    #/usr/bin/env蟒蛇3
    从键入导入联合
    def foo(b:Union[str,int])->int:
    def bar(a:Union[int,str]=b)->int:#参数“a”的默认值不兼容(默认值的类型为“Union[str,int]”,参数的类型为“int”)
    断言isinstance(a,int)
    返回a+1
    如果存在(b,str):
    返回条(0)
    其他:
    返回条()
    印刷品(foo(3))#4
    打印(foo(“你好”)#1
    

    不过,这个解决方案并不完美,因为如果您遵循函数签名并向其传递一个字符串,它将失败(由于
    断言
    )。因此,它需要对函数本身进行一些内省,以确定实际可以传递的内容。

    如果类型签名不是函数所期望的,那么强制执行类型签名会让人感到尴尬。您的
    bar
    函数显然需要一个
    int
    ,并且在类型提示上强制一个
    联合
    ,只是为了稍后断言您实际上只接受
    int
    应该不必为mypy静音

    由于您正在接受
    b
    作为bar中的默认值,因此应注意
    bar
    中的
    str
    大小写,因为
    b
    的类型签名已在
    foo
    中指定。两种我认为更适合当前问题的替代解决方案:

    def foo(b: Union[str, int]) -> int:
    
        # bar takes care of the str case. Type of b already documented
        def bar(a=b) -> int:
            if isinstance(b, str):
                return bar(0)
            return a + 1
    
        return bar()
    
    在定义
    条之前定义默认值:

    def foo(b: Union[str, int]) -> int:
    
        x: int = 0 if isinstance(b, str) else b
    
        # bar does not take a default type it won't use.
        def bar(a: int = x) -> int:
            return a + 1
    
        return bar()
    

    这个默认值甚至不应该存在。编写此代码的安全方法是

    def foo(b: Union[str, int]) -> int:
        def bar(a) -> int:
            return a + 1
    
        if isinstance(b, str):
            return bar(0)
        else:
            return bar(b)
    
    我不知道是什么情况促使你问这个问题,但不管你真正想写什么程序,你可能也不应该有一个默认的参数值


    您的代码与尝试执行的代码非常相似

    def f(x: Union[int, str]) -> int:
        y: int = x
        if isinstance(x, str):
            return 1
        else:
            return y + 1
    
    这样写,显然
    y
    是错误的。我们不应该给静态类型的变量赋值
    int
    def f(x: Union[int, str]) -> int:
        def g(y: int = x):
            pass
        return 4