我目前正在阅读FastAPI的教程用户指南,而Pylance抛出了以下警告:

No overloads for "update" match the provided argumentsPylancereportCallIssue
typing.pyi(690, 9): Overload 2 is the closest match

Here是抛出警告的代码:

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/")
async def read_items(q: str | None = None):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q}) # warning here
    return results

我try 将Python › Analysis: Type Checking Mode更改为basic,并使用Pylance的预发布版本,但警告仍然存在.

推荐答案

您被智能类型推理咬了一口.为了清楚起见,我将摆脱对FastAPI的依赖,并在一个更简单的 case 中重现:

foo = {"foo": ["bar"]}
foo["bar"] = "baz"

mypy(或pylance)错误我附近没有Pylance,所以让我们坚持mypy -问题是一样的,措辞可能会有所不同.

E:赋值中的类型不兼容(表达式的类型为"str",目标的类型为"list[str]")[赋值]

现在应该清楚了:foo在第一次赋值时被推断为dict[str, list[str]].我们可以加reveal_type来确认,这是the playground.现在,类型判断器理所当然地抱怨道:您正试图将值类型为list[str]的dict中的值设置为str.馊主意.

那么,现在怎么办?您需要告诉TypeChecker,您不希望推理如此精确.您的选项很少(以下任一选项都可以):

from typing import Any, TypedDict, NotRequired

class Possible(TypedDict):
    foo: list[str]
    bar: NotRequired[str]

foo: dict[str, Any] = {"foo": ["bar"]}
foo: dict[str, object] = {"foo": ["bar"]}
foo: dict[str, list[str] | str] = {"foo": ["bar"]}
foo: Possible = {"foo": ["bar"]}

有什么区别?

  • object是一种"就是某样东西"的类型--一种你几乎一无所知的类型.您不能将对象相加或相乘,也不能将它们传递给需要某些特定类型的函数,但可以打印它.我认为这个解决方案最适合您的用例,因为之后您不需要对判据做任何操作.
  • Possible TypedDict是这里的亚军:如果这个字典定义了一些重要的 struct ,你在以后的处理中经常使用这些 struct ,你最好清楚地说出每个键的意思.
  • Any意味着"离我远点,我知道我在做什么".这可能是一个很好的解决方案,如果你稍后使用这个字典-object将需要大量的类型缩小才能使用,而Any就可以了.
  • UNION解决方案是最差的,除非您的键是真正动态的(没有语义意义).每当您try 将值用作两种联合类型中的任何一种时,类型判断器都会向您喊话-它总是可以是另一种类型.(这不是一个通用的建议:对于键不表示JS对象之类的 struct 的情况,dict[str, int | str]可能是一个很好的类型)

因此,在您的特定情况下

@app.get("/items/")
async def read_items(q: str | None = None):
    results: dict[str, object] = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q}) # warning here
    return results

应该会通过.

既然你和其他回答者被过载误导了,下面是MutableMapping.update(dict个子类MutableMapping在存根中)在typeshed中的样子:

class MutableMapping(Mapping[_KT, _VT]):
    ...  # More methods
    
    @overload
    def update(self, __m: SupportsKeysAndGetItem[_KT, _VT], **kwargs: _VT) -> None: ...
    @overload
    def update(self, __m: Iterable[tuple[_KT, _VT]], **kwargs: _VT) -> None: ...
    @overload
    def update(self, **kwargs: _VT) -> None: ...

根据皮兰斯的说法,我不知道为什么"超载2是最接近的匹配",但你当然应该击中第一个.

Python相关问答推荐

Polars比较了两个预设-有没有方法在第一次不匹配时立即失败

将特定列信息移动到当前行下的新行

Python中的嵌套Ruby哈希

在Pandas DataFrame操作中用链接替换'方法的更有效方法

如何从在虚拟Python环境中运行的脚本中运行需要宿主Python环境的Shell脚本?

为什么默认情况下所有Python类都是可调用的?

我如何根据前一个连续数字改变一串数字?

在www.example.com中使用`package_data`包含不包含__init__. py的非Python文件

如何禁用FastAPI应用程序的Swagger UI autodoc中的application/json?

如何在PySide/Qt QColumbnView中删除列

幂集,其中每个元素可以是正或负""""

为什么调用函数的值和次数不同,递归在代码中是如何工作的?

如何按row_id/row_number过滤数据帧

30个非DATETIME天内的累计金额

如何在Gekko中使用分层条件约束

在用于Python的Bokeh包中设置按钮的样式

在Django中重命名我的表后,旧表中的项目不会被移动或删除

利用SCIPY沿第一轴对数组进行内插

一维不匹配两个数组上的广义ufunc

将索引表转换为Numy数组