如何强制子类使用 __init_subclass__ 而不是 ABCMeta 来实现父类的抽象方法?

2023-12-27

我有以下代码来将所需函数的基类的当前(空)实现与其子类进行比较,子类必须以某种不同的方式实现它们,以便在运行时被认为是可接受的。不使用metaclass=ABCMeta并实施@abstractmethod这些基类方法上的装饰器,我该如何去做呢?现在,我正在写以下内容__init_subclass__在我的项目中的多个地方挂接我的临时的、无元类的抽象基类,但感觉不对。

import inspect

class AbstractThing:
    def __init__(self, topic: str, thing: Thing):
        thing.subscriptions[topic] = self.on_message
        thing.on_connected.append(self.on_connected)
        thing.on_disconnected.append(self.on_disconnected)

    def __init_subclass__(cls):
        required_methods = ['on_connected', 'on_disconnected', 'on_message']
        for f in required_methods:
            func_source = inspect.getsourcelines(getattr(cls, f))
            # if this class no longer inherits from `Object`, the method resolution order will have updated
            parent_func_source = inspect.getsourcelines(getattr(cls.__mro__[-2], f))
            if func_source == parent_func_source:
                raise NotImplementedError(f"You need to override method '{f}' in your class {cls.__name__}")

    def on_connected(self, config: dict):
        pass

    def on_disconnected(self):
        pass

    def on_message(self, msg: str):
        pass

有一个更好的方法吗?如果我在定义此子类时可以在编辑器中出现类型检查错误,那就加分了AbstractThing.


事实上,你不应该依赖inspect.getsourcelines对于任何应该在严肃的环境中使用的代码(即实验领域之外,或处理源代码本身的工具)

简单明了is运算符足以检查给定类中的方法是否与基类中的方法相同。 (在 Python 3 中。Python 2 用户必须注意将方法检索为unbound methods而不是原始函数)

除此之外,您还需要经过几次不必要的轮转才能到达基类本身 -很少有记录并且很少使用特殊变量__class__ https://docs.python.org/3/reference/datamodel.html#creating-the-class-object可以帮助您:它是对编写它的类主体的自动引用(不要误认为self.__class__这是对子类的引用)。

从文档中:

此类对象将以零参数形式引用super(). __class__是编译器创建的隐式闭包引用,如果类体中的任何方法引用其中之一__class__ or super. 这允许零参数形式super()正确识别正在定义的类基于词法作用域,而用于进行当前调用的类或实例是根据传递给该方法的第一个参数来识别的。

因此,在保持主要方法的同时,整个事情可以变得非常简单:

def __init_subclass__(cls):
    required_methods = ['on_connected', 'on_disconnected', 'on_message']
    for f in required_methods:
         if getattr(cls, f) is getattr(__class__, f):
              raise NotImplementedError(...)

如果您有一个复杂的层次结构,并且父类具有其他强制方法,这些方法的子类必须实现这些方法 - 因此,无法在required_methods,您仍然可以使用abstractmethod装饰器来自abc,不使用ABCMeta元类。装饰器所做的就是在元类上检查的方法上创建一个属性。只需在 a 中进行相同的检查__init_subclass__ method:

from abc import abstractmethod

class Base:
   def __init_subclass__(cls, **kw):
        super().__init_subclass__(**kw)
        for attr_name in dir(cls):
            method = getattr(cls, attr_name)
            if (getattr(method, '__isabstractmethod__', False) and
                    not attr_name in cls.__dict__):
                # The second condition above allows 
                # abstractmethods to exist in the class where 
                # they are defined, but not on further subclasses
                raise NotImplementedError(...)

class NetworkMixin(Base):
    @abstractmethod
    def on_connect(self):
         pass

class FileMixin(Base):
    @abstractmethod
    def on_close(self):
         pass

class MyFileNetworkThing(NetworkMixin, FileMixin):
    # if any of the two abstract methods is not
    # implemented, Base.__init_subclass__ will fail

请记住,这只是检查类中出现的方法”dir。但定制__dir__很少使用,因此它是可靠的 - 只需注意记录即可。

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

如何强制子类使用 __init_subclass__ 而不是 ABCMeta 来实现父类的抽象方法? 的相关文章

随机推荐

  • 格式化文件路径

    我是 Python 新手 所以我的做法可能完全错误 但我在获取和更改文件目录时遇到问题 我的脚本接受可以位于任何目录中的多个文件名 在我的脚本中 我需要 python 更改到文件的目录 然后执行一些操作 但是 我在更改目录时遇到问题 这是我
  • 使用 Rstudio 实时预览 Rmarkdown 文档

    我一直使用 VScode 作为主要的记笔记平台 并且我已经非常习惯实时预览功能 现在我必须使用 Rmarkdown 生成可更新的报告 我想知道是否有人知道如何使用 Rstudio 生成实时预览 我对有关 R 和 Rmarkdown 的 Vs
  • 如何使用AWS Cognito作为单点登录?

    我有 2 个网站 用户注册 登录和其他内容 将在 认知用户池 用户个人资料 自我保健 两个站点位于不同的域中 如何在两个站点之间实施 SSO 是的 您可以通过以下方式进行操作 登录在第一个站点上完成 您将获得一个令牌 在第二个站点上使用此令
  • OAuth2FeignRequestInterceptor 的替代方案,因为它现已弃用

    在我之前的实现中 我使用的是 OAuth2FeignRequestInterceptor 但从 Spring security 5 开始 OAuth2FeignRequestInterceptor 似乎已被弃用 有什么替代方法可以达到同样的
  • 尝试在 Eclipse 中创建新项目时出现“构建路径条目丢失”错误

    缺少构建路径条目 org eclipse jdt launching JRE CONTAINER org eclipse jdt internal debug ui launcher StandardVMType JavaSE 1 7 当我
  • 如何使用 SwiftUI DocumentGroup 读取大文件而不制作临时副本?

    我制作了一个 SwiftUI DocumentApp 它可以读取大型媒体文件 但不需要写入它们 在我的文档中 我只想存储文件的 URL 以便我可以使用例如加载它 AVAudioFile 如果不像作者那样创建文件的临时副本 我无法弄清楚如何执
  • 确定mysql中列允许的最大长度

    表的结构如下 registrant id varchar 16 registrant name varchar 128 我想运行一个查询来显示与最大允许长度匹配的所有条目 即我当前对上述内容所做的操作 SELECT FROM tm regi
  • localeCompare 进行自然排序?

    我正在开发一个漫画书阅读器 我有一些用户上传的文件 图像 文件对象 我正在使用它们的文件名以便按正确的顺序对它们进行排序 我尝试使用localeCompare对它们进行自然排序 但没有运气 页面应按以下方式排序 page1 page2 pa
  • 水晶报表无法运行 Azure Web 应用程序

    我们在 ASP NET 应用程序中使用水晶报表 https kegxchange azurewebsites net https kegxchange azurewebsites net 然而 当我们发布应用程序时 我们收到错误 无法加载文
  • 如何回收Java线程堆栈使用的内存?

    我已经遇到这个内存泄漏问题好几天了 我想我现在有了一些线索 我的记忆java进程不断增长 但堆却没有增加 有人告诉我 如果我创建许多线程 这是可能的 因为 Java 线程使用堆之外的内存 我的java进程是一个服务器类型程序 所以有1000
  • 哪个是 Rails 应用程序的最佳数据库?

    我正在开发一个 Rails 应用程序 它将访问大量 RSS 提要或抓取数据站点 主要是新闻 它将类似于 Google 新闻 但采用不同的方法 因此我将存储大量新闻 或新闻摘要 将它们分类为不同的类别 并使用排名和推荐技术 我应该选择 MyS
  • Angular HttpClient 结合管道、点击和订阅?

    我正在尝试使用 Angular 中的 HttpClient 检索一些数据 我的代码如下所示 getData suffurl string id number Observable
  • Angular 2 RxJS检查鼠标事件在延迟后是否仍然活动

    我正在使用 Angular 2 来制定指令 我将以下事件绑定到主机组件 host mouseenter onMouseEnter event mouseleave onMouseLeave event 我还在指令上创建了两个流和侦听器来管理
  • 是否有可能破解并更新 Firebase 实时数据库数据

    最近我使用 Firebase 构建了一个应用程序 但是在我通过广告获得了一些用户后 有人刚刚入侵了 Firebase 数据库并更新了所有用户数据 例如 用户名 个人资料图片路径 他们将其设置为不好的词和不好的图片 然后我还检查了 Fireb
  • Safari 9 中后退按钮后触发 JQuery/Javascript

    当我使用 Chrome Firefox 中的浏览器后退按钮向后导航时 我的网站按预期工作 与不向后导航而加载的情况相同 在 Safari 中 导航回来后 我无法触发任何 加载 类型的事件 无论标准文档是否准备就绪 还是在 StackOver
  • Android:如何将rtmp流地址发送到外部视频播放器(例如MX播放器)

    就像我的问题所述 如何将 rtmp 流地址发送到外部媒体播放器 Mx Player 能够播放我的流 但我无法将地址发送给它 我试过这个 String videoUrl rtmp mystream Intent i new Intent an
  • 如何使用 Python 从文本 (str) 中提取和增加小时

    例如我有这个文本 输入 Event Time Monday 10 01 02 269 to 10 01 08 702 Reported by John Event Time Sunday 20 01 08 931 to 20 01 15 2
  • 在SqlPackage.exe部署的dacpac中创建用户导致登录失败SqlException

    Problem 我正在尝试自动化 SQL 部署 包括用户和角色 当我在 Sql Management Studio 中创建用户时它可以工作 但是当我部署 dacpack 时 我得到 SqlException Login Failed for
  • 比较 Mongoose Doc 中的日期并表达当前日期

    我正在查找正在提交 POST 请求的用户 然后查明他们是否拥有与他们尝试提交的同一架构中的文档 如果有多个 我会排序并返回最新的一个 我想将当前日期与 mongoose 文档中找到的日期进行比较 看看他们在过去 30 天内是否执行了相同的操
  • 如何强制子类使用 __init_subclass__ 而不是 ABCMeta 来实现父类的抽象方法?

    我有以下代码来将所需函数的基类的当前 空 实现与其子类进行比较 子类必须以某种不同的方式实现它们 以便在运行时被认为是可接受的 不使用metaclass ABCMeta并实施 abstractmethod这些基类方法上的装饰器 我该如何去做