在添加类型提示时遇到的问题

前端开发 2026-07-08

问题现已编辑为仅讨论一个错误,因为管理员因包含太多错误而对其进行了屏蔽。请注意,之所以列出所有错误,是因为它们可能相关:

在PyCharm中解决剩余的类型提示问题时有些困难。

代码:

from wsgiref.types import StartResponse
import importlib.util
import importlib.machinery

interactive_mode = True
if interactive_mode:
    from collections.abc import Callable
    import logging
    from wsgiref import simple_server

class WsgiController:

    def __init__(self, environ: dict[str, str], start_response: StartResponse) -> None:
        self.oPage = Process(environ, start_response)

httpd = simple_server.make_server("", 8000, WsgiController)

class Request:

    def __init__(self, environ: dict[str, str]) -> None:
        self.environ = environ

    def get(self, key: str) -> str | None:
        return self.environ.get(key)

    def parse_cookies(self) -> None:
        _ = self.get("HTTP_COOKIE")

    def set_cookie(self, attributes: None | dict[str, str] = None) -> None:
        _ = self
        if attributes is None: attributes = {}
        for _, _ in attributes.items():
            pass

class Response:
    start_response: Callable[[str, list[tuple[str, str]]], None]

    def __init__(self, start_response) -> None:
        self.start_response = start_response
        self.headers = [("", "")]

    def serve_pre_compiled(self) -> str:
        local_dict = {"oRequest": Process.oRequest, "oResponse": self}
        return local_dict["__HTML__"]

    def serve_new_source(self, source_file: str, module_name: str, pyc_file: str) -> str:
        spec = importlib.util.spec_from_file_location(module_name, source_file)
        if spec is not None and spec.loader is not None:
            importlib.util.module_from_spec(spec)
            module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(module)
        _ = self
        _ = pyc_file
        return _

class Process:
    oRequest: Request
    oResponse: Response
    logger: logging.Logger
    def __init__(self, environ, start_response: StartResponse) -> None:
        _ = self.oResponse.start_response.__self__.status
        Process.oRequest = Request(environ)
        Process.oResponse = Response(start_response)

下一个错误:

Member 'None' of 'dict[str, str] | None' does not have attribute 'items'
    for _, _ in attributes.items():

解决方案

  1. 在你的代码中你说你有:

py def set_cookie(self, attributes: None | dict[str, str] = None) -> None: _ = self if attributes is None: attributes = {} for _, _ in attributes.items(): pass

关于你提到的错误:

console Member 'None' of 'dict[str, str] | None' does not have attribute 'items' for _, _ in attributes.items():

该错误表示你的类型提示允许它具有 type == None,这与 type == type(None) 不同,因此如果 type = None,错误的含义是:hasattr(type, "items") is False

不过,这个问题因用局部变量 attributes 覆盖参数而有点复杂(从技术上讲并非错误,只是在阅读和调试时会显得有点误导

正如 @Hayden T. Brown 的注释所提,你应该尝试像下面这样:

_attributes: dict[str, str] = attributes if attributes else {}

完整函数(已修补):

    def set_cookie(self, attributes: None | dict[str, str]) -> None:
        # if you must use 'self' to make a poorly tuned linter happy try this:
        if not self: return None  # e.g., must never happen
        # keep the local var _attributes as a strict type dict[str, str]
        _attributes: dict[str, str] = attributes if attributes else {}
        for _, _ in _attributes.items():
            pass

  1. 事后改进:

你也可以在 def 表达式中使用 {} 的默认值;例如:

    def set_cookie(self, attributes: dict[str, str] = {}) -> None:
        if not self: return None  # e.g., must never happen
        _attributes: dict[str, str] = attributes if attributes else {}
        for _, _ in _attributes.items():
            pass

这将使 def 的意图与类型提示与语义行为保持一致。需要注意的是,用显式的 None 调用 some_request.set_cookie(None) 在类型提示上被视为对你代码的API违规(尽管实现仍然会处理),并可能被lint工具标记。


  1. 为了减少lint的噪音,来自评论中的讨论(当你不想使用Python的默认可变参数时)

你甚至可以在此时从 def 表达式中省略默认值;例如:

    def set_cookie(self, attributes: dict[str, str]) -> None:
        if not self: return None  # e.g., must never happen
        _attributes: dict[str, str] = attributes if attributes else {}
        for _, _ in _attributes.items():
            pass

然而,通过省略默认参数,以及一个 None-类型的类型提示,调用方每次都需要传入一个 dict[str, str],以便与你的类型提示对齐(请参考前面的第一种做法作为推荐);例如,需要 some_request.set_cookie(attributes={}) 而不是 some_request.set_cookie()(尽管Python运行时当然仍然接受两者,因为类型提示是给开发者看的,而不是给运行时用的)

另请参阅官方文档以解释这种误导性错误:

相关问题:

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章