首页 > 编程问答 >如何为可以在递归调用中重新分配的 python 函数制定类型提示?

如何为可以在递归调用中重新分配的 python 函数制定类型提示?

时间:2024-08-04 16:16:12浏览次数:13  
标签:python python-typing mypy

采取以下最小示例:

S = TypeVar("S", bound=int | str)

def meth(a: S) -> S:
    if a == "5":
        return str(meth(int(a)))

    return a

特别是,上面的方法可以采用字符串或整数。它总是返回与其输入相同类型的值,但它可以递归地调用自身,在这种情况下, S 的值可能需要重新分配。使用上面的类型提示,mypy 给出错误:

error: Incompatible return value type (got "str", expected "S")  [return-value]

我如何正确输入上面的函数?

编辑 : 谢谢,很高兴知道 == 不执行类型缩小。但是,我仅将其用于我的最小示例。我的实际用例的简化版本如下所示:

T = TypeVar("T", bound=CSTNode)

def _rec_set_docstring(expr: T, new_str: str) -> T:
    if isinstance(expr, (BaseSuite, SimpleStatementLine)):
        return expr.with_changes(
            body=(_rec_set_docstring(expr.body[0], new_str),)
        )

    if not isinstance(expr, Expr):
        raise ValueError
    if isinstance(expr.value, (SimpleString, ConcatenatedString)):
        return expr.with_changes(value=expr.value.with_changes(value=new_str))
    raise ValueError

这依赖于 libcs​​t ,但最相关的签名应该是 CSTNode

_CSTNodeSelfT = TypeVar("_CSTNodeSelfT", bound="CSTNode")
@dataclass(frozen=True)
class CSTNode(ABC):
    def with_changes(self: _CSTNodeSelfT, **changes: Any) -> _CSTNodeSelfT:
        ...

问题在于你的类型提示告诉 mypy meth 对于同一种类型始终返回相同类型的 S ,但这并非事实。在某些情况下,它返回 str(meth(int(a))) 的结果,该结果始终为 str ,而不管 S 是什么。

你无法在 mypy 当前的类型系统中准确地表达这一点。根本原因是 mypy 不执行类型缩小,因此它不知道在 if 语句的主体中, a 的类型为 str

你有几个选择:

  1. 忽略错误。 如果确定代码正确,可以安全地忽略类型检查器错误。

```python S = TypeVar("S", bound=int | str)

def meth(a: S) -> S: # type: ignore[return-value] if a == "5": return str(meth(int(a))) return a ```

  1. 使用 cast 这告诉 mypy 你比它更了解类型。

```python from typing import cast

S = TypeVar("S", bound=int | str)

def meth(a: S) -> S: if a == "5": return cast(S, str(meth(int(a)))) return a ```

  1. 重构你的代码。 通常,解决此类类型错误的最佳方法是重构代码,使其更易于进行类型检查。在本例中,你可以将函数拆分为两个单独的函数,一个用于整数,一个用于字符串。

```python def meth_int(a: int) -> int: ...

def meth_str(a: str) -> str: if a == "5": return str(meth_int(int(a))) return a ```

对于你的 _rec_set_docstring 示例,适用相同的原则。mypy 无法推断出 with_changes isinstance 检查后返回的类型与传入的类型相同。你可以通过以下方式解决此问题:

  1. 使用 cast

```python from typing import cast

T = TypeVar("T", bound=CSTNode)

def _rec_set_docstring(expr: T, new_str: str) -> T: if isinstance(expr, (BaseSuite, SimpleStatementLine)): return cast(T, expr.with_changes( body=(_rec_set_docstring(expr.body[0], new_str),) ))

   if not isinstance(expr, Expr):
       raise ValueError
   if isinstance(expr.value, (SimpleString, ConcatenatedString)):
       return cast(T, expr.with_changes(value=expr.value.with_changes(value=new_str)))
   raise ValueError

```

  1. 重构你的代码:

如果没有更具体的例子来说明你的 CSTNode 子类的结构以及你试图实现的目标,很难提供具体的重构建议。但是,一般来说,你可以考虑根据节点类型将函数拆分为更小的、类型更具体的函数。这将使 mypy 更容易跟踪类型并识别潜在问题。

标签:python,python-typing,mypy
From: 78829866

相关文章

  • 使用 python 和 json 抓取该网站的正确 URL 是什么?
    试图抓取这个网站-->https://ucr.gov/enforcement/1000511它曾经使用下面的代码,然后停止了。无法获取响应中的json或任何内容。query="1000511"url='https://ucr.gov/api/enforcement/{}'.format(query)headers={'User-Agent':'Mozilla/5.0(......
  • Python逆向
    参考链接:https://www.bilibili.com/video/BV1JL4y1p7Tt/?spm_id_from=333.999.0.0https://bbs.kanxue.com/thread-282542.htmhttps://blog.csdn.net/weixin_35967330/article/details/114390031?spm=1001.2014.3001.5501https://0xd13a.github.io/ctfs/0ctf2017/py/前言:py......
  • Python中使用正则表达式
    摘要:正则表达式,又称为规则表达式,它不是某种编程语言所特有的,而是计算机科学的一个概念,通常被用来检索和替换某些规则的文本。一.正则表达式的语法①行定位符行定位符就是用来描述字符串的边界。"^"表示行的开始,"$"表示行的结束。^tm  #tmequalTomorrowMoon可以......
  • 如何在python中使用xarray打开grib2文件?
    将xarray导入为xr导入cfgrib导入生态码将pandas导入为pddata=xr.open_dataset(r"C:\Users\new\forecast_data.grib2",engine="cfgrib")这是我的代码。我只想使用xarray读取这个文件。错误是:无法识别的引擎cfgrib必须是以下之一:['netcdf4'、'scipy'、'......
  • 如何在 java 或 python 中使用 HTTP(S) 解决无法解析的主机名或无法识别的名称错误?
    我尝试以编程方式访问网站的信息,但在Java和Python上都无法解析主机名。如果我指定IP地址,则会将错误更改为TLSV1_UNRECOGNIZED_NAME。不过,这个网站无需任何额外的工作就可以通过任何浏览器解决。我在这里浏览了很多潜在的解决方案,但对于Python,它说这个问题应该在2.7......
  • Python 请求 POST 请求与 websockets 库一起使用时挂起
    我使用Python中的requests库发送POST请求,同时维护与websockets库的WebSocket连接:importasyncioimportrequestsimportwebsocketsasyncdefwebsocket_handler(uri):asyncwithwebsockets.connect(uri)aswebsocket:whileTrue:me......
  • 在Python中,list1[::] = list2的空间复杂度是多少?
    此代码首先迭代列表nums,更新整数0、1、2(也分别称为红色、白色和蓝色)的计数。nums保证只有整数0、1和/或2。找到计数后,代码使用[::],这是一种就地修改列表的技巧,以排序numsdefsortColors(self,nums:List[int])->None:re......
  • [附开题]flask框架高校资产管理系统d8y3s(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育事业的快速发展,高校资产规模日益庞大,种类繁多,管理难度显著增加。传统的资产管理方式往往依赖于手工记录和纸质档案,不仅效率低......
  • [附开题]flask框架贺州图特产管理系统uuy79(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景贺州,这座历史悠久、文化底蕴深厚的城市,以其丰富的自然资源和独特的地理位置孕育了众多令人瞩目的特产。然而,在信息化快速发展的今天,贺州特......
  • [附开题]flask框架红枫超市会员管理系统ew5iq(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着零售行业的快速发展与消费者需求的日益多样化,超市作为人们日常生活中不可或缺的一部分,其管理效率和服务质量直接影响着顾客的购物体验......