首页 > 编程问答 >mypy 从被调用函数推断类型签名

mypy 从被调用函数推断类型签名

时间:2024-07-31 16:19:55浏览次数:13  
标签:python python-typing mypy

有没有办法从被调用函数推断调用者的类型签名?

在下面的示例中,(重载) Test1.f 函数按预期工作。 Test2.get_arg().f 也有效。

问题是:以类型安全的方式实现 Test2.f 的正确(最短)方法是什么,或者最接近的解决方法是什么? Test2.f 只是 Test2.get_arg().f 的快捷方式。如果可能的话,我想避免重复 Test2.f 的类型签名。

这是示例:

from typing import *

class Test1:
    @overload
    def f(self, key: Literal['A']) -> int: ...
    @overload
    def f(self, key: Literal['B']) -> str: ...
    def f(self, key: Any) -> Any:
        if key == 'A': return 1
        elif key == 'B': return 'x'
        assert_never(key)

class Test2:
    def __init__(self, arg: Test1):
        self._arg = arg

    def get_arg(self) -> Test1:
        return self._arg

    # How to tell to 'mypy' that 'f' is the same as 'get_arg().f',
    # without repeating the (overload) definition?
    # This works in runtime, but not for 'mypy'
    def f(self, key):
        return self.get_arg().f(key)

test2 = Test2(Test1())

# this works as expected
print(test2.get_arg().f('A') + 1)
#print(test2.get_arg().f('B') + 1) # <- mypy error (str + int)
#print(test2.get_arg().f('C')) # <- mypy error (no overload)

# we would like to have the same type safety with shortcut 'f'
print(test2.f('A') + 1)
#print(test2.f('B') + 1) # <- we want type error here
#print(test2.f('C')) # <- and here

我尝试过放置各种类型签名,例如:

def f(self, key: Any) -> Any:
def f(self, key: Union[Literal['A'], Literal['B']]) -> Any:

它修复了一些问题,但是 mypy 仍然不知道返回类型是什么。我不确定这种做法是否正确。


很遗憾,在不重复 Test1.f 的类型签名的情况下,你无法以 mypy 能够理解的方式直接表达 Test2.f Test2.get_arg().f 相同的事实。

这里的问题是 mypy 没有进行足够深入的代码流分析来理解 Test2.f 仅仅是委托给 self.get_arg().f

以下是几种解决方法,每种方法都有其优缺点:

1. 使用 cast

def f(self, key):
    return cast(Any, self.get_arg().f(key))  # type: ignore
  • 优点: 简单直接。
  • 缺点: 放弃了类型安全, mypy 不会捕获 Test2.f 调用中的类型错误。

2. 使用泛型

T = TypeVar('T')

class Test2:
    ...

    def f(self, key: str) -> T:
        return self.get_arg().f(key)  # type: ignore
  • 优点: 保留了一些类型安全, mypy 会根据调用 Test2.f 的位置推断返回类型。
  • 缺点: 仍然需要使用 type: ignore ,因为 mypy 不能保证 self.get_arg().f(key) 的返回值总是与 T 匹配。

3. 重复类型签名

    @overload
    def f(self, key: Literal['A']) -> int: ...
    @overload
    def f(self, key: Literal['B']) -> str: ...
    def f(self, key: Any) -> Any:
        return self.get_arg().f(key)
  • 优点: 提供最佳的类型安全, mypy 会完全理解 Test2.f 的类型行为。
  • 缺点: 需要重复代码,违背了你想要避免的目标。

4. 使用组合而不是继承

class Test2:
    def __init__(self, arg: Test1):
        self.arg = arg

    def f(self, key: str) -> Any:
        return self.arg.f(key)
  • 优点: 避免了重复类型签名,并保持了类型安全。
  • 缺点: 需要修改类的结构,可能不适用于所有情况。

哪种方法最适合你取决于你项目的具体情况和你对类型安全的容忍度。如果你绝对想要避免代码重复并且可以接受一些类型安全的损失,那么 cast 或泛型可能是合适的选择。如果你需要最高级别的类型安全,那么重复类型签名或使用组合是更好的选择。

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

相关文章

  • 《最新出炉》系列初窥篇-Python+Playwright自动化测试-60 - 判断元素是否显示 - 下篇
    1.简介有些页面元素的生命周期如同流星一闪,昙花一现。我们也不知道这个元素在没在页面中出现过,为了捕获这一美好瞬间,让其成为永恒。我们就来判断元素是否显示出现过。在操作元素之前,可以先判断元素的状态。判断元素操作状态也可以用于断言。2.常用的元素判断方法2.1page对象调......
  • 是否有可能在Python中获取客户端计算机的位置
    我想编写一个程序,用python查找客户端计算机的位置。不过,我不介意它的格式如何。我到处尝试过一些东西,但老实说,我对这类事情了解不多,所以我真的不知道从哪里开始。|||我想简单地运行该程序,并将运行该程序的客户端计算机的位置写入控制台。Iwouldliketosimplyrunt......
  • Python:使用 Selenium WebDriver 无法在客户端打开浏览器
    我使用SeleniumWebDriver开发了一个应用程序来打开一些页面。它在本地工作得很好,但我还需要在客户端启动浏览器。我使用Apache2underUbuntu18部署了应用程序。driver=webdriver.Chrome(executable_path="chromedriver",chrome_options=ch......
  • Python:使用默认模块在python中读取excel
    我有Python2.6.6版本,但无法安装pandas、xlrd、xlwt等新模块。我想使用Python读取Excel。是否可以使用Python中存在的默认模块读取Excel。抱歉,不能使用Python2.6.6的默认模块读取Excel文件。Python没有内置的功能来处理Excel文件。使用外部库(如提......
  • 【Python】从0开始写脚本、Selenium详细教程、附源码案例(保姆篇)
    文章目录准备工作安装selenium配置浏览器驱动脚本测试什么是Selenium?Selenium功能示例(可直接拷贝执行)编写一个简单的Python脚本来使用Selenium打开一个网页,并获取网页的标题下面是一个示例,自动打开csdn并进行搜索Selenium使用Selenium元素定位文本输入、清除与提交......
  • Python控制台输出的华丽变身:色彩与风格的深度探索
    一、文章摘要本文深入探讨了Python标准输出中字体颜色的设置方法,特别是通过ANSI转义序列实现的文本样式控制。文章详细解析了ANSI转义序列的组成、各个颜色代码的含义,以及如何在Python中使用这些代码来改变终端输出的字体颜色、背景色、高光、加粗等样式。通过丰富的案例代码,......
  • 二十五、【机器学习】-【Python手搓3层神经网络】:从零构建深度学习模型的实战指南
    目录一、序章:为什么你需要掌握手搓神经网络二、基础篇:神经网络基础知识回顾三、实战配置:搭建3层神经网络的步骤与技巧(一)、__init__ 方法初始化神经网络(二)、train 方法实现了前向传播和反向传播(三)、query 方法(四)、全部代码四、总结一、序章:为什么你需要掌握手......
  • 在Python中将简单的字典导出到Excel文件中
    我是Python新手。我有一个简单的字典,其键和值如下dict1={"numberofstoragearrays":45,"numberofports":2390,......}我需要将它们放入Excel表中,如下numberofstoragearrays45numberofports2390我有一个非常大的字典。importpandasasp......
  • 将 python 脚本作为 AWS 胶水服务作业运行
    我有一个使用本地路径在本地运行的python脚本,但我需要复制此python脚本并将其作为AWS胶水服务作业运行并将输出保存在s3存储桶中。请帮助我逐步说明。将Python脚本作为AWSGlue作业运行的步骤如下:步骤1:修改的Python脚本以使其与Glue兼容......
  • Python - Decorating classes
    Whenwetalkaboutdecoratingclasses,wecaneitherdecorateindividualmethodsorwecancreateadecoratortodecoratethewholeclass.classMyClass:def__init__(self,a):self.a=a@timerdefmethod1(self,x,y):print......