实现模仿QFileSystemModel的Protocol时遇mypy兼容性错误
解决QFileSystemModel派生类适配自定义Protocol时的mypy签名冲突问题
核心问题根源
Qt的QFileSystemModel继承自QAbstractItemModel,它的index方法有两个重载:
- 标准行列索引重载:
index(row: int, column: int, parent: QModelIndex = ...) -> QModelIndex - 文件路径专属重载:
index(path: str) -> QModelIndex
你的自定义FileSystemModelProtocol如果没有严格对齐这两个重载的参数名、类型、默认值,mypy就会判定Qt基类的实现与Protocol不兼容。之前把第二个重载的path改成row,会直接破坏签名匹配,导致“重载函数实现不接受签名2的所有参数”错误。
正确的Protocol定义
要让Protocol与Qt的实现完全兼容,必须用@overload明确声明两个重载的签名,和Qt的实现保持一致:
from typing import Protocol, overload from PyQt6.QtCore import QModelIndex class FileSystemModelProtocol(Protocol): @overload def index(self, row: int, column: int, parent: QModelIndex = ...) -> QModelIndex: ... @overload def index(self, path: str) -> QModelIndex: ... # 占位实现,用于满足Protocol的方法定义要求 def index(self, *args, **kwargs) -> QModelIndex: ...
适配派生类的正确方式
因为QFileSystemModel本身已经实现了符合要求的index重载,你的自定义类不需要额外重写该方法,直接继承即可:
from PyQt6.QtGui import QFileSystemModel class CustomFileSystemModel(QFileSystemModel, FileSystemModelProtocol): # 这里可以添加自定义逻辑,无需重写index pass
若需自定义index方法
如果必须重写index,要确保重载签名完全对齐Protocol和Qt基类:
class CustomFileSystemModel(QFileSystemModel, FileSystemModelProtocol): @overload def index(self, row: int, column: int, parent: QModelIndex = ...) -> QModelIndex: ... @overload def index(self, path: str) -> QModelIndex: ... def index(self, *args, **kwargs) -> QModelIndex: # 自定义逻辑示例:比如日志记录后调用父类实现 print(f"Calling index with args: {args}, kwargs: {kwargs}") return super().index(*args, **kwargs)
关键注意事项
- 必须严格匹配Qt方法的参数名:比如第一个重载的
row/column/parent不能改,第二个重载的path也不能替换成其他名称。 - 默认值要保留:第一个重载的
parent参数有默认值...(对应Qt的默认QModelIndex()),Protocol中必须声明这个默认值。 - mypy对重载的匹配非常严格,任何签名细节(包括参数顺序、类型、默认值、参数名)不一致都会触发兼容性错误。
内容的提问来源于stack exchange,提问作者shao.lo
相关产品推荐
相关产品推荐

