首页 > 编程问答 >非泛型类方法上的字典类型变量

非泛型类方法上的字典类型变量

时间:2024-07-25 05:58:09浏览次数:7  
标签:python annotations python-typing mypy

在以下代码中:

from typing import Generic
from typing import TypeVar
from typing import reveal_type


T = TypeVar('T')


class Field(Generic[T]):
    """A field definition with a default value."""

    def __init__(self, default_value: T):
        self.default_value = default_value


class FieldDataCollection:
    """A collection of field values."""

    def __init__(self, value_per_field: dict[Field[T], T]) -> None:
        self._value_per_field = value_per_field

    def get_field_value(self, field: Field[T]) -> T:
        """Return the field value if in the collection or the field default value."""
        return self._value_per_field.get(field, field.default_value)


if __name__ == '__main__':
    foo = Field(1)
    value = FieldDataCollection({foo: 2}).get_field_value(foo)
    reveal_type(value)

在严格模式下运行 1.11.0(但不是以前的版本)时,我从 mypy 中得到以下错误:

error: Incompatible return value type (got "T@__init__", expected "T@get_field_value")  [return-value]
error: Argument 1 to "get" of "dict" has incompatible type "Field[T@get_field_value]"; expected "Field[T@__init__]"  [arg-type]
error: Argument 2 to "get" of "dict" has incompatible type "T@get_field_value"; expected "T@__init__"  [arg-type]
note: Revealed type is "builtins.int"

据我对这些错误的理解,mypy 抱怨在 | 中推断的类型||方法与 __init__ 方法中的类型有些不同。 get_field_value 我尝试为

使用不同类型的变量: get_field_value 但是mypy似乎捕捉到了差异并以相同的方式抱怨:

T = TypeVar("T")
Tfield = TypeVar("Tfield")

...

class FieldDataCollection:
    ...

    def get_field_value(self, field: Field[Tfield]) -> Tfield:
        ...

我尝试使用

error: Incompatible return value type (got "T", expected "Tfield")  [return-value]
error: Argument 1 to "get" of "dict" has incompatible type "Field[Tfield]"; expected "Field[T]"  [arg-type]
error: Argument 2 to "get" of "dict" has incompatible type "Tfield"; expected "T"  [arg-type]
note: Revealed type is "builtins.int"

Mapping 代替 MutableMapping ,效果很好,但是我不能使用 dict 之类的方法 dict copy 你认为这是mypy方面的回归吗? 否则,您知道如何正确注释

类吗? FieldDataCollection class properly?


遇到的问题是 mypy 正确地标识了代码中的一个类型不一致问题,尽管此问题可能很微妙,并且在早期版本中未被发现。

问题分解:

  1. 类型变量范围: FieldDataCollection __init__ 方法中,使用 dict[Field[T], T] 。这里的 T 是一个类型变量,它的作用域仅限于该方法。这意味着每次实例化 FieldDataCollection 时, T 都可以代表不同的类型。

  2. 不一致的使用: get_field_value 方法中,再次使用 T ,但它指的是在 __init__ 中定义的 T 相同 实例。然而,没有理由相信传递给 get_field_value Field[T] 与用于实例化 FieldDataCollection Field[T] 使用相同的 T

Mypy 的抱怨是有效的:

Mypy 在 1.11.0 版本中加强了对类型变量范围的检查。它现在正确地识别出 __init__ get_field_value 中的 T 可能代表不同的类型,因此它标记了这些不一致性。

解决方案:

为了解决这个问题,需要确保 T 在整个 FieldDataCollection 类中表示相同的类型。可以通过使 FieldDataCollection 本身成为泛型来实现:

from typing import Generic, TypeVar

T = TypeVar('T')

class Field(Generic[T]):
    def __init__(self, default_value: T):
        self.default_value = default_value

class FieldDataCollection(Generic[T]):
    def __init__(self, value_per_field: dict[Field[T], T]) -> None:
        self._value_per_field = value_per_field

    def get_field_value(self, field: Field[T]) -> T:
        return self._value_per_field.get(field, field.default_value)

if __name__ == '__main__':
    foo = Field(1)
    value = FieldDataCollection({foo: 2}).get_field_value(foo)
    reveal_type(value)  # note: Revealed type is "builtins.int"

解释:

通过使 FieldDataCollection 成为泛型,现在可以确保 T 在整个类的范围内表示相同的类型。这意味着传递给 __init__ get_field_value Field 实例必须具有相同的类型参数。

结论:

这不是 mypy 的回归,而是在类型检查方面的一项改进。通过理解类型变量的范围和正确使用泛型,可以解决这个问题并提高代码的类型安全性。

标签:python,annotations,python-typing,mypy
From: 78790692

相关文章

  • VS Code Python - 如果括号(括号、大括号等)未关闭,内联建议不起作用
    我遇到的问题是,当我在未闭合的括号或方括号“内部”开始变量名称时,VSCode将不会显示任何建议。但是,如果在键入变量名称之前闭合括号,则建议效果很好。如果我可以避免它,我宁愿不将自动完成括号关闭设置为True也不使用TabOut扩展。第一个屏幕截图显示建议在闭括号/方......
  • 在 Azure 上部署代码时使用 Python 的多处理模块是否有意义?
    我们的团队在Azure机器学习(AML)上部署了一个Python脚本来处理存储在Azure存储帐户上的文件。我们的管道由一个ForEach活动组成,该活动调用每个或列出的文件的Python脚本。从Azure数据工厂(ADF)运行它会触发多个单独的管道同时运行......
  • 我已成功安装 pypdf2 但无法将其导入到我的 python 文件中
    我已经成功安装了pypdf2模块,但在导入它时,我发现该模块丢失了。我尝试使用fromPyPDF2importPdfReader导入,但它不起作用此问题的各种解决方案是什么?在尝试导入PyPDF2时遇到问题。以下是可能导致此问题的一些常见原因和解决方案:安......
  • Python3打开图片时请求ConnectionResetError(10054)
    我试图从'http://xxx.jpg'之类的网站下载图片。代码:headers={'user-agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/66.0.3359.139Safari/537.36'}url='http://xxx.jpg'resp......
  • Jupyter Notebook 环境中的 Python 版本不匹配
    我遇到Jupyter笔记本启动横幅中报告的Python版本与我在笔记本中查询python--version时显示的版本之间的差异。启动横幅指示Python3.11.9,但是当我运行!python--version时,它返回Python3.11.7。我所做的步骤:basecondahas3.11.7versio......
  • Python XML 解析:字符串中的“<”被阻塞
    我有一个使用ET.XMLParser来解析CppCheckXML报告文件的Python模块。当尝试解析字符串中包含“<”的XML元素中的属性之一时,它会令人窒息,它会将其解释为格式错误的XML,例如:<errormsg="Includefile<iostream>notfound.">(注意字符和“iostream”之间的空格必须放......
  • 任意几行代码要成为Python中的函数需要什么?
    我正在上一门计算机科学课,我的任务是创建一个程序来实现一个带有参数的函数。我的老师告诉我,下面的代码不是一个函数,这让我很困惑,对于将某些代码行归类为“函数”所需的条件,我感到很困惑。defgame(numbers,max_turns,pfl,tgl):turns=0flag=Falseprint("You......
  • 如何使用 Python 创建新的 Azure 订阅?
    我正在尝试使用PythonSDK以编程方式创建新的Azure订阅。我发现的对AzurePythonSDK的唯一引用是这个这是我最终得到的结果:importazure.mgmt.billingimportazure.mgmt.subscriptioncreds=AzureCliCredential()client_name='test'defcreat......
  • 用于打印脚本输出的 Python 实用程序
    我可以发誓有一个实用程序可以打印一个python脚本,其输出交织在一起。例如,给定一个脚本:a=2b=3print(a+b)print(a*b)该实用程序将输出a=2b=3print(a+b)#>5print(a*b)#>6有人知道该实用程序的名称吗?我最难找到它。谢谢你!描述的实用程序没有标......
  • a method to make some handy tools with python
    Inmyworkingofcomputer,therearealotofsimplejobsthatarefrequentlyrepeated.Itriedtofindawaytomakethesejobbeenprocessedeasily.Method1:Themethodiswritingascripttodothejob,andexecutingthescriptbyutoolsextensionuto......