python - 如何使用 MYPY 传递关键字参数?
问题描述
认为:
def foo(biz: str = 'biz',baz: str = 'baz', *args:Any, **kwargs:Any)-> str:
return biz + baz
我像这样使用它:
def bar(ness: str = 'ness', *args, **kwargs):
return foo(biz=ness, *args, **kwargs)
请注意,这个目标(指定关键字并传递 args + kwargs)掩盖了我对 args 的一些其他误解:在 python 中,args 在设置了具有默认值(关键字 arg)的 arg 之后无法传入,正如下面正确指出的那样..
然后mypy
版本 0.812 会抛出如下错误:
$: mypy --ignore-missing-imports --disallow-untyped-defs --disallow-incomplete-defs
foo/foo.py:6: error: "foo" gets multiple values for keyword argument "biz"
有没有办法解决这个问题,特别是除了下面的返回线之外的任何地方都没有做出重大改变?
return foo(biz=ness, *args, **kwargs)
解决方案
根据您的回答,我将假设您希望 linter 传递 的定义bar
,并且您愿意bar
为此目的对 的实现/声明进行更改。
对我来说,根本问题是 的实现bar
是错误的——如果*args
不为空,那么调用foo(biz=ness, *args, **kwargs)
将失败,并且与 mypy 报告的错误完全相同。
def foo(biz: str = 'biz',baz: str = 'baz', *args:Any, **kwargs:Any)-> str:
return biz + baz
def bar_from_question(ness: str = 'ness', *args, **kwargs):
return foo(biz=ness, *args, **kwargs)
>>> bar_from_question("1")
1baz
>>> bar_from_question("1", "2")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/jean/Projects/python/test-mypy/test.py", line 7, in bar_from_question
return foo(biz=ness, *args, **kwargs)
TypeError: foo() got multiple values for argument 'biz'
对我来说,你有三个选择:
foo
通过不再传递来修复调用args
。这样的更改不会导致功能损失,因为无论如何都会有一个非空args
的。在这种情况下,您还可以从 of 的签名中删除(同样,在不丢失功能的情况下 - 您只需将调用触发的 a 替换为调用中的a )bar
TypeError
args
bar
TypeError
foo
TypeError
bar
def bar_do_not_pass_args_to_foo(ness: str = 'ness', *args, **kwargs): return foo(biz=ness, **kwargs) def bar_remove_args_from_signature(ness: str = 'ness', **kwargs): return foo(biz=ness, **kwargs)
foo
通过biz
作为位置参数而不是命名参数传递来修复调用:def bar_pass_biz_as_positional(ness: str = 'ness', *args, **kwargs): return foo(ness, *args, **kwargs)
向 mypy 隐藏问题(我从您的回答中了解到)
def bar_hide_from_mypy(ness: str = 'ness', *args, **kwargs): kwargs['biz'] = ness return foo(*args, **kwargs)
但是,如果目标是简单地防止 mypy 报告错误,则可以使用以下语法:
def bar_suppress_mypy(ness: str = 'ness', *args, **kwargs): return foo(biz=ness, *args, **kwargs) # type: ignore
现在,如果我在运行时解释器中比较每个提案的结果:
>>> bar_do_not_pass_args_to_foo("1")
'1baz'
>>> bar_do_not_pass_args_to_foo("1", "2")
'1baz'
>>> bar_remove_args_from_signature("1")
'1baz'
>>> bar_remove_args_from_signature("1", "2")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bar_remove_args_from_signature() takes from 0 to 1 positional arguments but 2 were given
>>> bar_pass_biz_as_positional("1")
'1baz'
>>> bar_pass_biz_as_positional("1", "2")
'12'
>>> bar_hide_from_mypy("1")
'1baz'
>>> bar_hide_from_mypy("1", "2")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/jean/Projects/python/test-mypy/test.py", line 20, in bar_hide_from_mypy
return foo(*args, **kwargs)
TypeError: foo() got multiple values for argument 'biz'
>>> bar_suppress_mypy("1")
'1baz'
>>> bar_suppress_mypy("1", "2")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/jean/Projects/python/test-mypy/test.py", line 23, in bar_suppress_mypy
return foo(biz=ness, *args, **kwargs) # type: ignore
TypeError: foo() got multiple values for argument 'biz'
你可以看到:
- 对于返回结果的每种情况
bar_from_question
,所有其他bar_...
实现都返回相同的结果; - 除了 mypy 之外的所有实现都
bar_from_question
保持沉默,我的印象是你想要的;
在您的情况下,我会寻求潜在问题的解决方案(即应用要点 1 或 2),而不仅仅是试图强制 mypy(要点 3)。
推荐阅读
- firebase - Firebase ID 问题
- r - “标记”ggplot2中的刻度线?
- python - 将日期时间对象插入 BigQuery 时,Google Cloud 函数崩溃
- ruby-on-rails - 如何建立这种多态关系?
- c++ - 使用宏来摆脱依赖的模板关键字是个好主意吗?
- python - 无法从 xpath 获取价值
- python - Git 最佳实践:如何构建一个大型应用程序所需的多个 python 模块
- function - 使用功能 swiftUI 将视图添加到 contentView 不起作用
- multipartform-data - 如何解释缺少 CRLF 的多部分?
- azure - 将 Function App 连接到特定设备?