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没有意识到这一点
我怎么能
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