如何获取格式而不导致类型提示错误?

问题描述 投票:0回答:1

我在 Python 中有以下列表推导式:

from typing import cast

# everything is fine
print([value for value in [1, 2, 3, 4]])

# on the first "value": Expression type contains "Any" (has type "List[Any]")
print("{}".format([value for value in [1, 2, 3, 4]]))

# on the "cast": Expression type contains "Any" (has type "List[Any]")
print("{}".format([cast(int, value) for value in [1, 2, 3, 4]]))

为什么使用

format
会导致 Mypy 返回错误?正如你所看到的,我尝试使用强制转换,但仍然失败。

这个问题看起来很相似,但我的特殊情况很奇怪,因为只要我不使用

format
函数,Mypy 似乎就很好(但使用
print
函数总是没问题)。

我能做些什么来避免格式化行给我带来错误吗? (或者我应该只是

# type: ignore
他们?)

编辑: 请注意,这似乎不仅仅是我的 Atom linter 的问题。 我正在使用 Mypy 版本

0.701
,并在文件上运行 Mypy,结果如下:

$ python3 -m mypy testing_list_iter.py --disallow-any-expr
testing_list_iter.py:7: error: Expression type contains "Any" (has type "List[Any]")
testing_list_iter.py:10: error: Expression type contains "Any" (has type "List[Any]")
python list-comprehension python-typing mypy
1个回答
5
投票

这实际上与列表推导无关:这实际上是

str.format(...)
的类型签名、mypy 如何执行类型推断和
--disallow-any-expr
标志之间的不良交互。

这是

str.format(...)
的类型签名,从 typeshed 中提取:

def format(self, *args: Any, **kwargs: Any) -> str: ...

当 mypy 对函数调用执行类型推断时,它将尝试使用声明的参数类型来帮助为您传入的表达式提供上下文。

所以在这种情况下,由于参数都是

Any
,mypy 会意识到它可以简化很多通常需要做的类型推断。因此,如果我们将任何列表文字传递给
str.format(...)
,mypy 将决定“嘿,推断的类型可以只是
List[Any]
”。

这是一个演示此行为的示例程序(当使用

--disallow-any-expr
标志检查时):

from typing import cast, Any

def test1(x: Any) -> None:
    pass

def test2(x: object) -> None:
    pass

# Revealed type is 'builtins.list[Any]'
# Expression type contains "Any" (has type "List[Any]")
test1(reveal_type([1, 2, 3, 4]))

# Revealed type is 'builtins.list[builtins.int*]'
test2(reveal_type([1, 2, 3, 4]))

请注意,当我们尝试使用接受

object
而不是
Any
的函数时,mypy 将推断完整类型而不是执行此快捷方式。 (Mypy 在技术上可以做同样类型的快捷方式,因为所有类型也是
object
的子类,但我怀疑这只是更简单的实现方式——与
Any
不同,
object
只是一个普通的普通旧类型所以与它的特殊外壳交互有点奇怪。)

通常,mypy 如何准确地处理这种情况并不重要:无论哪种方式,您都可以获得准确的结果。

但是,

--disallow-any-expr
标志仍然相当新且相对未经测试(对于很多人来说,它太激进了,尤其是那些试图在现有代码库上使用 mypy 的人),因此我们时不时会遇到这些糟糕的交互。


那么,解决办法是什么?

最好的修复方法是您向 Typeshed 提交拉取请求,修改

builtins.pyi
文件中的
str.format(...)
unicode.format(...),以便它们接受对象而不是
Any

无论如何,此更改将符合 Typeshed 的贡献指南——具体来说,“约定”部分中间的这段代码:

添加类型提示时,请尽可能避免使用

Any
类型。保留使用
Any
的时间:

  • 当前类型系统无法表达正确的类型;和
  • 以避免联合退货(见上文)。

请注意,如果您想指示某个函数实际上可以接受任何内容,则

Any
不是正确的类型:在这些情况下,请使用
object
代替。

然后,等待 mypy 的下一个版本,理论上应该很快就会发布。

同时,您可以做的就是将列表理解的结果分配给一个新变量,然后将 that 传递到

str.format(...)
:

results = [value for value in [1, 2, 3, 4]]
print("{}".format(results))

这将导致 mypy 在没有

Any
上下文的情况下推断列表推导的类型,从而推断出完整的类型。这避免了与
--disallow-any-expr
标志的不良交互。

© www.soinside.com 2019 - 2024. All rights reserved.