首页 > 编程问答 >如何在Python中继承类型提示?

如何在Python中继承类型提示?

时间:2024-07-27 04:14:45浏览次数:11  
标签:python python-typing mypy

所以我的问题是,当我有一个 A 类型的类来做事情并且我使用这些函数作为 subclass(B) 时,它们仍然是类 A 的类型,并且不接受我的类 B 对象作为参数或作为函数签名。

我的问题简化了:

from typing import TypeVar, Generic, Callable

T = TypeVar('T')


class Signal(Generic[T]):
    def connect(self, connector: Callable[[T], None]) -> None:
        pass

    def emit(self, payload: T):
        pass


class A:
    def __init__(self) -> None:
        self.signal = Signal[A]()

    def do(self) -> None:
        self.signal.emit(self)

def handle_b(b: "B") -> None:
    print(b.something)

class B(A):
    def __init__(self) -> None:
        super().__init__()
        self.signal.connect(handle_b)

    @property
    def something(self) -> int:
        return 42

我也可以提供完整的信号类,但这只会分散对问题的注意力。这给我在 mypy 中留下了一个错误:

error: Argument 1 to "connect" of "Signal" has incompatible type Callable[[B], None]; expected Callable[[A], None]

由于信号处理是在 A 子类中实现的 B 不能期望 B 类型对象被返回,即使它显然应该没问题......


遇到的问题在于,在定义 Signal[A] 时,类型提示会变得具体化,并且不知道将来会有 B 子类 A

可以通过以下几种方法解决此问题:

1. 使用 TypeVar 绑定到 A 的子类:

from typing import TypeVar, Generic, Callable

T = TypeVar('T', bound='A')  # 将 T 限制为 A 的子类


class Signal(Generic[T]):
    def connect(self, connector: Callable[[T], None]) -> None:
        pass

    def emit(self, payload: T):
        pass


class A:
    def __init__(self) -> None:
        self.signal: Signal[A] = Signal()  # 明确指定 Signal[A]

    def do(self) -> None:
        self.signal.emit(self)

def handle_b(b: "B") -> None:
    print(b.something)

class B(A):
    def __init__(self) -> None:
        super().__init__()
        self.signal.connect(handle_b)  # 现在可以接受 handle_b

    @property
    def something(self) -> int:
        return 42

在这个版本中, T 被限制为 A 或其任何子类,因此 Signal[A] 可以接受 B 类型的对象。

2. 在子类中重新定义 signal 类型:

from typing import Callable

# ... (Signal 类定义不变)

class A:
    def __init__(self) -> None:
        self.signal: Signal[A] = Signal()

    def do(self) -> None:
        self.signal.emit(self)

def handle_b(b: "B") -> None:
    print(b.something)

class B(A):
    signal: Signal['B']  # 重新定义 signal 类型

    def __init__(self) -> None:
        super().__init__()
        self.signal.connect(handle_b)

    @property
    def something(self) -> int:
        return 42

在这个版本中,我们在 B 类中重新定义了 signal 的类型注释,使其更具体为 Signal['B']

这两种方法都可以解决的问题,选择哪种方法取决于的具体需求和代码结构。

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

相关文章

  • mypy:方法的参数与超类型不兼容
    看示例代码(mypy_test.py):importtypingclassBase:deffun(self,a:str):passSomeType=typing.NewType('SomeType',str)classDerived(Base):deffun(self,a:SomeType):pass现在mypy抱怨:mypymypy_test.pymypy_test.......
  • Python - 如何传递类对象的函数参数类型(打字)
    我想python3.7附带了(不确定),不仅可以将变量名传递给函数,还可以传递变量的类型。我想知道的是是否有可能传递特定类的类型。以同样的方式传递:deffoo_func(i:int)->None:pass如果我有一个类,让我们说:classfoo_class(object):pass我如何转换fo......
  • 使用 Python 构建简单 REST API
    使用Python构建简单RESTAPI1.概述本技术文档旨在指导开发者使用Python框架Flask构建一个基本的RESTAPI。通过学习本指南,您将掌握创建、读取、更新和删除(CRUD)操作的基本知识,并能够使用Python构建自己的API。2.安装依赖首先,您需要确保已安装Python和Flask......
  • Python——Pandas(第二讲)
    文章目录变量类型的转换Pandas支持的数据类型在不同数据类型间转换建立索引新建数据框时建立索引读入数据时建立索引指定某列为索引列将索引还原变量列引用和修改索引引用索引修改索引修改索引名修改索引值更新索引Series的索引和切片DataFrame的索引和切片选择列按......
  • 基于Python+Django的红色文化研学网站设计与实现
    ......
  • 【python】对网站进行请求-初识
    python实现对网站进行请求代码如下importrequestsdefget_data(url,headers=None,params=None,timeout=10):try:res=requests.get(url,headers=headers,params=params,timeout=timeout)res.raise_for_status()returnres.text......
  • 【python】Django初识-从未有如此美妙的开局
    Django初识python、Django安装与验证python安装Python官网https://www.python.org/Django安装pipinstallDjango验证python是否安装成功python--version验证Django是否安装成功python3-mdjango--version创建第一个Django项目项目创建与服务器启动打开cmd,输......
  • Python虚拟环境创建、激活、使用,项目依赖导出、安装requestments.txt
    Python虚拟环境通过命令行终端创建python虚拟环境:新建一个文件夹,可以专门用来存放虚拟环境,这里在D盘创建Python_Virtual_Environment_test文件夹然后在这里输入cmd按回车键进入命令行终端此时打开的位置就是当前的路径,当然也可以 cd一步步进入到目标路径创建环境......
  • 使用 Python 脚本自动生成报告
    使用Python脚本自动生成报告1.简介本文档介绍如何使用Python脚本自动生成报告。此脚本旨在简化报告生成过程,提高效率并减少人为错误。2.需求Python3.6或更高版本Pandas库Matplotlib库3.安装使用pip安装必要的库:pipinstallpandasmatplotlib4.脚本im......
  • 【和为 K 的子数组】python刷题记录
    这就到前缀和了。classSolution:defsubarraySum(self,nums:List[int],k:int)->int:#连续不能sortnum=len(nums)i=0j=i+1sm=0ret=0#j可以=是因为后面切片不包括jwhilej<=num:......