如何向 mypy 指示对象具有某些属性?

2023-12-30

我正在使用一些从父类派生的类(Widget);在孩子们中,有些人具有某些属性(posx and posy)但有些则不然。

import enum
from dataclasses import dataclass
from typing import List


class Color(enum.IntEnum):
    GLOWING_IN_THE_DARK = enum.auto()
    BROWN_WITH_RAINBOW_DOTS = enum.auto()


@dataclass
class Widget:
    """Generic class for widget"""


@dataclass
class Rectangle(Widget):
    """A Color Rectangle"""

    posx: int
    posy: int
    width: int = 500
    height: int = 200
    color: Color = Color.BROWN_WITH_RAINBOW_DOTS


@dataclass
class Group(Widget):
    children: List[Widget]


@dataclass
class Button(Widget):
    """A clickable button"""

    posx: int
    posy: int
    width: int = 200
    height: int = 100
    label: str = "some label"

即使仅使用具有这些属性的小部件进行一些过滤后,mypy无法认识到他们应该认识到的。

有没有办法表明mypy我们有一个具有给定属性的对象?

例如,以下函数和调用:

def some_function_that_does_something(widgets: List[Widget]):
    """A useful docstring that says what the function does"""
    widgets_with_pos = [w for w in widgets if hasattr(w, "posx") and hasattr(w, "posy")]

    if not widgets_with_pos:
        raise AttributeError(f"No widget with position found among list {widgets}")

    first_widget = widgets_with_pos[0]
    pos_x = first_widget.posx
    pos_y = first_widget.posy
    print(f"Widget {first_widget} with position: {(pos_x, pos_y)}")


some_widgets = [Group([Rectangle(0, 0)]), Button(10, 10, label="A button")]
some_function_that_does_something(some_widgets)

将返回预期的结果:Widget Button(posx=10, posy=10, width=200, height=100, label='A button') with position: (10, 10)

But mypy会抱怨:

__check_pos_and_mypy.py:53: error: "Widget" has no attribute "posx"
        pos_x = first_widget.posx
                ^
__check_pos_and_mypy.py:54: error: "Widget" has no attribute "posy"
        pos_y = first_widget.posy
                ^
Found 2 errors in 1 file (checked 1 source file)

怎么做?

也许,一种方法是改变类的设计:

  • 的子类Widget与位置(例如WidgetWithPos)
  • Rectangle and Button将从这个类派生
  • 我们在函数中指出:widget_with_pos: List[WidgetWithPos] = ...

...但是,我无法改变课程的原始设计mypy可能仍然会抱怨类似的事情:

List comprehension has incompatible type List[Widget]; expected List[WidgetWithPos]

当然,我们可以放一堆# type:ignore但这会使代码变得混乱,我相信有一种更聪明的方法;)

Thanks!


这是 Alex Waygood 的一个小变化answer https://stackoverflow.com/a/69336474/1393162,删除cast。诀窍是把@runtime_checkable https://docs.python.org/3.9/library/typing.html#typing.runtime_checkableProtocol 类上的装饰器。它只是让isinstance() do the hasattr() checks.

import sys
from dataclasses import dataclass
from typing import List

# Protocol has been added in Python 3.8+
# so this makes the code backwards-compatible
# without adding any dependencies
# (typing_extensions is a MyPy dependency already)

if sys.version_info >= (3, 8):
    from typing import Protocol, runtime_checkable
else:
    from typing_extensions import Protocol, runtime_checkable


@dataclass
class Widget:
    """Generic class for widget"""


@runtime_checkable
class WithPos(Protocol):
    """Minimum interface of all widgets that have a position"""
    posx: int
    posy: int


def some_function_that_does_something(widgets: List[Widget]):
    """A useful docstring that says what the function does"""
    widgets_with_pos = [w for w in widgets if isinstance(w, WithPos)]

    if not widgets_with_pos:
        raise AttributeError(f"No widget with position found among list {widgets}")

    first_widget = widgets_with_pos[0]
    pos_x = first_widget.posx
    pos_y = first_widget.posy
    print(f"Widget {first_widget} with position: {(pos_x, pos_y)}")

以下代码(使用原始问题中定义的其他子类):

w1 = Group([])
w2 = Rectangle(2, 3)
some_function_that_does_something([w1, w2])

进一步阅读

作为参考,以下是 Alex 在其答案中包含的一些链接:

  • Python 文档 https://docs.python.org/3/library/typing.html#typing.Protocol for typing.Protocol
  • PEP 544 https://www.python.org/dev/peps/pep-0544/,介绍typing.Protocol并解释结构子类型的概念。
  • MyPy 文档 https://mypy.readthedocs.io/en/stable/protocols.html for Protocols 和结构子类型。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何向 mypy 指示对象具有某些属性? 的相关文章

随机推荐

  • 将多个帧发送到AWS rekognition

    我正在尝试从我的网络摄像头将图片发送到 aws rekognition 以使用 python 检测坐在它前面的人的活动 为此 我每 5 秒拍一张照片并将其发送到 aws 但当我这样做时 他似乎总是发回有关我发送的第一帧的信息 cap cv2
  • 防止缓存 CSS 文件

    我正在使用 PHP 开发一个简单的网站 开发配置 WAMP 生产配置 LAMP 在测试时 我更改了 CSS 文件 但是当我重新加载页面时 我的浏览器 不确定 仍然使用旧的缓存 css 我做了一些谷歌搜索 发现了我已经尝试过的不同解决方案 在
  • Android开发字符串数组资源太大,导致Android应用程序崩溃!

    我有一个字符串数组资源 其中包含大约 1000 个药物名称
  • 在 PowerShell 中使用 WinSCP 仅下载新文件

    如何下载最新文件或某天发布的文件 导入包含以下内容的 CSV 文件Source and a 目的地柱子 需要检查路径是否存在 文件是否存在并且仅下载新文件 现在的脚本正在将所有文件移动到相应的文件夹 但是一旦我再次运行脚本 它不仅仅下载新文
  • 强制转换为“void”到底有什么作用? [复制]

    这个问题在这里已经有答案了 经常使用的语句 例如 void x 允许抑制有关未使用变量的警告x 但是如果我尝试编译以下内容 我会得到一些我不太理解的结果 int main int x short x void x int x 用 g 编译它
  • CBCentralManager 连接是否超时?

    我知道答案名义上是 不 但我的意思是really 如果应用程序进入后台 启用 BTLE 后台处理 会怎样 24小时 跨应用程序更新 在 重新连接到外围设备 标题下 苹果文档 https developer apple com library
  • 当需要 getter 和 setter 方法时如何在 Python 模块之间共享变量

    如果我需要这些变量具有 setter 和 getter 方法 如何在 Python 项目的不同模块之间共享变量 我需要 setter getter 方法的原因是 在获取和设置变量时 我需要与将这些变量存储为环境变量的代码向后兼容 所以我也需
  • java.sql.SQLException:未知的系统变量“query_cache_size”

    我有一个使用 JDBC 运行的应用程序并从 MySQL 获取数据 但由于以下错误我无法构建它 java sql SQLException Unknown system variable query cache size at com mys
  • 当我在 Project Explorer 中选择文件时,如何让 Eclipse 自动打开/预览文件

    当我在 Project Explorer 中选择文件时 有没有办法让 Eclipse 自动打开 预览文件 我知道我可以双击 但我想在探索项目时快速向上 向下箭头 我本质上是在寻找 Mac Finder 快速查看或 Windows 7 资源管
  • 如何检索给定相对路径的绝对路径

    是否有命令可以检索给定相对路径的绝对路径 例如我希望 line 包含 dir 中每个文件的绝对路径 etc find type f while read line do echo line done Try realpath sudo ap
  • jquery div 是否包含某个类的子级

    我有一个事件处理程序 它触发一个事件处理程序 该事件处理程序需要测试 div 的子级是否包含某个类 现在 我正在这样做 Container DivData live mouseenter function if this find Hidd
  • 类型“typeof StoreModule”上不存在属性“provideStore”

    我认为他们发布了一些重大更改 这是我收到的错误消息 类型 typeof StoreModule 上不存在属性 provideStore 我用谷歌搜索了这个错误消息 但没有找到任何东西 尽管如此 我猜还是有一些我不知道的 API 更新 有人能
  • .net core 跨平台桌面应用

    我想使用 net Core 开发一个跨平台桌面应用程序 该应用程序需要在 Linux Mac os 和 Windows 上执行 为此 我应该创建一个控制台应用程序并将以下行放入设置 xml 中吗
  • 如何在 C# 中通过 FileStream 和 ResumableUploader 上传/更新文件

    我想通过 Google Documents List API C 中的 System IO FileStream 上传 更新文件 我使用以下两种方式 Google GData Client ResumableUpload Resumable
  • 如何在 Eclipse EE Luna 中分析 Java Web 应用程序 servlet 调用

    在我的 Web 应用程序中 servlet 甚至在开始写入响应之前也需要几秒钟的时间 我想知道 servlet 执行期间调用了哪些方法以及每个方法花费的时间 Luna 版本中是否已包含分析器面向 Java EE 开发人员的 Eclipse
  • 如何使用TableAdapter进行更新?

    我正在写一个程序WindowsApplication其中使用数据库 我显示数据库值DataGridView 目前 我希望可以通过以下方式更新数据库DataGridView 因此我写了这段代码 private void MainForm Lo
  • 使用github写一本书[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 使用 Github 我们可以编写格式良好的 README md 文件和文档来展示项目 此外 还有供用户协作的 wiki 页面 我正在思
  • 确定触摸移动的垂直方向

    我正在尝试为平板电脑实现一个触摸监听器 以触发一些操作 具体取决于触摸是向上还是向下移动 我尝试了本机监听器 document bind touchmove function e alert it worked but i don t kn
  • Lisp/Scheme 中的 '(撇号)是什么?

    我正在自学计划的第一天第一个小时 不用说 我什么也不明白 所以我正在读书小阴谋家并使用这个东西 http sisc scheme org sisc online php http sisc scheme org sisc online ph
  • 如何向 mypy 指示对象具有某些属性?

    我正在使用一些从父类派生的类 Widget 在孩子们中 有些人具有某些属性 posx and posy 但有些则不然 import enum from dataclasses import dataclass from typing imp