重构:使用实例参数重载方法的类型安全方法是什么,例如方法(自己,其他)?

2024-05-26

我想将以下内容重构为类型安全的内容。我现在给出了 mypy“与超类型不兼容”错误。

我理解这是由于里氏替换原则:

  • 子类型中方法参数的逆变。
  • 子类型中返回类型的协方差。

也就是说(如果我理解正确的话),我可以返回A or a subtype of A,但我只能通过A or a 超型 of A(两者都不会有b属性)到 B.add。

所以,我“不能”做我一直在做的事情,我正在寻找一种重构方法(更多代码见下文)。

# python 3.7

class A:
    def __init__(self, a: int) -> None:
        self.a = a

    def add(self, other: "A") -> "A":
        return type(self)(a=self.a + other.a)


class B(A):
    def __init__(self, a: int, b: int) -> None:
        super().__init__(a=a)
        self.b = b

    def add(self, other: "B") -> "B": # Argument 1 of "add" incompatible with supertype "A"
        return type(self)(a=self.a + other.a, b=self.b + other.b)

我唯一想到的是某种父母类型A and B没有add method.

class SuperAB:
    # doesn't add
    pass

class A(SuperAB):
    # has add method
    pass

class B(SuperAB):
    # has add method
    pass

这看起来很混乱,但如果这是“Pythonic”要做的事情,我会同意的。我只是想知道是否还有其他方法(除了 # type:ignore 之外)。

解决方案:

在玩了“打地鼠”并遇到各种类型错误后,我在 StackOverflow 答案的帮助下得到了这个:

T = TypeVar("T")

class A(Generic[T]):
    def __init__(self, a: int) -> None:
        self.a = a

    def add(self, other: T) -> "A":
        return type(self)(a=self.a + getattr(other, "a"))


class B(A["B"]):
    def __init__(self, a: int, b: int) -> None:
        super().__init__(a=a)
        self.b = b

    def add(self, other: T) -> "B":
        return type(self)(
            a=self.a + getattr(other, "a"), b=self.b + getattr(other, "b")
        )

请注意,我做不到self.a + other.a因为我会看到一个"T" has no attribute "a"错误。上面的方法可行,但感觉这里的受访者比我知道的更多,所以我采取了他们的real建议并重构。

我见过足够多的人知道是正确的一条建议是“B 应该haveA,不是beA。”我承认这超出了我的理解范围。Bhas和 int (实际上是两个,B.a 和 B.b)。这些整数会做整数所做的事情,但是,为了B.add(B),我必须以某种方式将这些整数放入另一个 B 中,如果我希望“以某种方式”具有多态性,我就回到了开始的地方。我显然遗漏了一些关于 OOP 的基本知识。


我可能不会B继承自A。也就是说,对于以下情况B应该继承自A,您可能正在寻找在 Java 等事物中看到的那种模式可比 https://docs.oracle.com/javase/10/docs/api/java/lang/Comparable.html,其中类将子类作为类型参数:

from abc import ABCMeta, abstractmethod
from typing import Generic, TypeVar

T = TypeVar('T')

class A(Generic[T], metaclass=ABCMeta):
    @abstractmethod
    def add(self, other: T) -> T:
        ...

class B(A['B']):
    def add(self, other: 'B') -> 'B':
        ...

注意我已经标记了A抽象的,与add作为一个抽象方法。在这种情况下,根声明没有多大意义add成为一个具体的方法,或者一个具有具体方法的类add用具体的子类来子类化另一个类add.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

重构:使用实例参数重载方法的类型安全方法是什么,例如方法(自己,其他)? 的相关文章

  • 通过 Scrapy 抓取 Google Analytics

    我一直在尝试使用 Scrapy 从 Google Analytics 获取一些数据 尽管我是一个完全的 Python 新手 但我已经取得了一些进展 我现在可以通过 Scrapy 登录 Google Analytics 但我需要发出 AJAX
  • Python 中的 Lanczos 插值与 2D 图像

    我尝试重新缩放 2D 图像 灰度 图像大小为 256x256 所需输出为 224x224 像素值范围从 0 到 1300 我尝试了两种使用 Lanczos 插值来重新调整它们的方法 首先使用PIL图像 import numpy as np
  • 在 python 程序中合并第三方库的最佳实践是什么?

    下午好 我正在为我的工作编写一个中小型Python程序 该任务需要我使用 Excel 库xlwt and xlrd 以及一个用于查询 Oracle 数据库的库 称为CX Oracle 我正在通过版本控制系统 即CVS 开发该项目 我想知道围
  • Django 管理员在模型编辑时间歇性返回 404

    我们使用 Django Admin 来维护导出到我们的一些站点的一些数据 有时 当单击标准更改列表视图来获取模型编辑表单而不是路由到正确的页面时 我们会得到 Django 404 页面 模板 它是偶尔发生的 我们可以通过重新加载三次来重现它
  • 如何在flask中使用g.user全局

    据我了解 Flask 中的 g 变量 它应该为我提供一个全局位置来存储数据 例如登录后保存当前用户 它是否正确 我希望我的导航在登录后在整个网站上显示我的用户名 我的观点包含 from Flask import g among other
  • Python - StatsModels、OLS 置信区间

    在 Statsmodels 中 我可以使用以下方法拟合我的模型 import statsmodels api as sm X np array 22000 13400 47600 7400 12000 32000 28000 31000 6
  • Flask 会话变量

    我正在用 Flask 编写一个小型网络应用程序 当两个用户 在同一网络下 尝试使用应用程序时 我遇到会话变量问题 这是代码 import os from flask import Flask request render template
  • 如何在 Python 中检索 for 循环中的剩余项目?

    我有一个简单的 for 循环迭代项目列表 在某些时候 我知道它会破裂 我该如何退回剩余的物品 for i in a b c d e f g try some func i except return remaining items if s
  • PyUSB 1.0:NotImplementedError:此平台不支持或未实现操作

    我刚刚开始使用 pyusb 基本上我正在玩示例代码here https github com walac pyusb blob master docs tutorial rst 我使用的是 Windows 7 64 位 并从以下地址下载 z
  • Spark KMeans 无法处理大数据吗?

    KMeans 有几个参数training http spark apache org docs latest api python pyspark mllib html highlight kmeans pyspark mllib clus
  • 在Python中获取文件描述符的位置

    比如说 我有一个原始数字文件描述符 我需要根据它获取文件中的当前位置 import os psutil some code that works with file lp lib open path to file p psutil Pro
  • 如何使用Python创建历史时间线

    So I ve seen a few answers on here that helped a bit but my dataset is larger than the ones that have been answered prev
  • Jupyter Notebook 内核一直很忙

    我已经安装了 anaconda 并且 python 在 Spyder IPython 等中工作正常 但是我无法运行 python 笔记本 内核被创建 它也连接 但它始终显示黑圈忙碌符号 防火墙或防病毒软件没有问题 我尝试过禁用两者 我也无法
  • 如何在Python中对类别进行加权随机抽样

    给定一个元组列表 其中每个元组都包含一个概率和一个项目 我想根据其概率对项目进行采样 例如 给出列表 3 a 4 b 3 c 我想在 40 的时间内对 b 进行采样 在 python 中执行此操作的规范方法是什么 我查看了 random 模
  • 将图像分割成多个网格

    我使用下面的代码将图像分割成网格的 20 个相等的部分 import cv2 im cv2 imread apple jpg im cv2 resize im 1000 500 imgwidth im shape 0 imgheight i
  • 向 Altair 图表添加背景实心填充

    I like Altair a lot for making graphs in Python As a tribute I wanted to regenerate the Economist graph s in Mistakes we
  • 对年龄列进行分组/分类

    我有一个数据框说df有一个柱子 Ages gt gt gt df Age 0 22 1 38 2 26 3 35 4 35 5 1 6 54 我想对这个年龄段进行分组并创建一个像这样的新专栏 If age gt 0 age lt 2 the
  • 类型错误:预期单个张量时的张量列表 - 将 const 与 tf.random_normal 一起使用时

    我有以下 TensorFlow 代码 tf constant tf random normal time step batch size 1 1 我正进入 状态TypeError List of Tensors when single Te
  • 使用 Python 的 matplotlib 选择在屏幕上显示哪些图形以及将哪些图形保存到文件中

    我想用Python创建不同的图形matplotlib pyplot 然后 我想将其中一些保存到文件中 而另一些则应使用show 命令 然而 show 显示all创建的数字 我可以通过调用来避免这种情况close 创建我不想在屏幕上显示的绘图
  • 如何将输入读取为数字?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 Why are x and y下面的代码中使用字符串而不是整数 注意 在Python 2

随机推荐