Python abc 模块:扩展抽象基类和异常派生类会导致令人惊讶的行为

2024-05-22

扩展抽象基类和从“对象”派生的类可以按照您的预期工作:如果您尚未实现所有抽象方法和属性,则会出现错误。

奇怪的是,用扩展“Exception”的类替换对象派生类允许您创建不实现所有必需的抽象方法和属性的类的实例。

例如:

import abc

# The superclasses
class myABC( object ):
    __metaclass__ = abc.ABCMeta

    @abc.abstractproperty
    def foo(self):
        pass

class myCustomException( Exception ):
    pass

class myObjectDerivedClass( object ):
    pass

# Mix them in different ways
class myConcreteClass_1(myCustomException, myABC):
    pass

class myConcreteClass_2(myObjectDerivedClass, myABC):
    pass

# Get surprising results
if __name__=='__main__':
    a = myConcreteClass_1()
    print "First instantiation done. We shouldn't get this far, but we do."
    b = myConcreteClass_2()
    print "Second instantiation done. We never reach here, which is good."

...产量...

First instantiation done. We shouldn't get this far, but we do.
Traceback (most recent call last):
  File "C:/Users/grahamf/PycharmProjects/mss/Modules/mssdevice/sutter/sutter/test.py", line 28, in <module>
    b = myConcreteClass_2()
TypeError: Can't instantiate abstract class myConcreteClass_2 with abstract methods foo

我知道“Exception”因此“myCustomException”没有属性“foo”,那么为什么我要实例化“myCustomException”呢?

EDIT:根据记录,这是我最终采用的黑客解决方法。并不真正等同,但适合我的目的。

# "abstract" base class
class MyBaseClass( Exception ):
    def __init__(self):
        if not hasattr(self, 'foo'):
            raise NotImplementedError("Please implement abstract property foo")


class MyConcreteClass( MyBaseClass ):
    pass

if __name__=='__main__':
    a = MyConcreteClass()
    print "We never reach here, which is good."

看起来这是因为__new__方法用于BaseException不关心抽象方法/属性。

当你尝试实例化时myConcreteClass_1,它最终调用__new__来自Exception班级。当想要实例化时myConcreteClass_2,它调用__new__ from object:

>>> what.myConcreteClass_1.__new__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: exceptions.Exception.__new__(): not enough arguments
>>> what.myConcreteClass_2.__new__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object.__new__(): not enough arguments

The Exception类不提供__new__方法,但它是父方法,BaseException, does http://hg.python.org/cpython/file/db302b88fdb6/Objects/exceptions.c#l31:

static PyObject *
BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    PyBaseExceptionObject *self;

    self = (PyBaseExceptionObject *)type->tp_alloc(type, 0);
    if (!self)
        return NULL;
    /* the dict is created on the fly in PyObject_GenericSetAttr */
    self->dict = NULL;
    self->traceback = self->cause = self->context = NULL;
    self->suppress_context = 0;

    if (args) {
        self->args = args;
        Py_INCREF(args);
        return (PyObject *)self;
    }

    self->args = PyTuple_New(0);
    if (!self->args) {
        Py_DECREF(self);
        return NULL;
    }

    return (PyObject *)self;
}

将此与__new__实施object http://hg.python.org/cpython/file/db302b88fdb6/Objects/typeobject.c#l3233:

static PyObject *
object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    if (excess_args(args, kwds) &&
        (type->tp_init == object_init || type->tp_new != object_new)) {
        PyErr_SetString(PyExc_TypeError, "object() takes no parameters");
        return NULL;
    }

    if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) {
        PyObject *abstract_methods = NULL;
        PyObject *builtins;
        PyObject *sorted;
        PyObject *sorted_methods = NULL;
        PyObject *joined = NULL;
        PyObject *comma;
        _Py_static_string(comma_id, ", ");
        _Py_IDENTIFIER(sorted);

        /* Compute ", ".join(sorted(type.__abstractmethods__))
           into joined. */
        abstract_methods = type_abstractmethods(type, NULL);
        if (abstract_methods == NULL)
            goto error;
        builtins = PyEval_GetBuiltins();
        if (builtins == NULL)
            goto error;
        sorted = _PyDict_GetItemId(builtins, &PyId_sorted);
        if (sorted == NULL)
            goto error;
        sorted_methods = PyObject_CallFunctionObjArgs(sorted,
                                                      abstract_methods,
                                                      NULL);
        if (sorted_methods == NULL)
            goto error;
        comma = _PyUnicode_FromId(&comma_id);
        if (comma == NULL)
            goto error;
        joined = PyUnicode_Join(comma, sorted_methods);
        if (joined == NULL)
            goto error;

        PyErr_Format(PyExc_TypeError,
                     "Can't instantiate abstract class %s "
                     "with abstract methods %U",
                     type->tp_name,
                     joined);
    error:
        Py_XDECREF(joined);
        Py_XDECREF(sorted_methods);
        Py_XDECREF(abstract_methods);
        return NULL;
    }
    return type->tp_alloc(type, 0);
}

如你看到的object.__new__当存在未被重写的抽象方法时,有代码抛出错误,但是BaseException.__new__才不是。

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

Python abc 模块:扩展抽象基类和异常派生类会导致令人惊讶的行为 的相关文章

  • Python - 定义常量列表或字典的最佳/最简洁的方法

    第一次使用堆栈溢出 我很高兴来到这里 简介 我最近开始了 Python 编程世界的神奇冒险 我喜欢它 现在 在我从 C 语言的尴尬过渡中 一切都进展顺利 但我在创建与标头文件 h 同义的内容时遇到了麻烦 问题 我有中等大小的字典和列表 大约
  • 在 MacOSX10.6 上运行 python 服务器时 MySQLdb 错误

    运行我的服务器 python manage py runserver 产生以下错误 django core exceptions ImproperlyConfigured 加载 MySQLdb 模块时出错 没有名为 MySQLdb 的模块
  • AttributeError:模块“tensorflow.python.framework.ops”没有属性“RegisterShape”

    我正在使用 TensorFlow 2 1 0 dev20191125 不幸的是 我无法编译一个带有错误的简单示例 AttributeError 模块 tensorflow python framework ops 没有 属性 Registe
  • PyQt4 信号和槽

    我正在使用 PyQt4 编写我的第一个 Python 应用程序 我有一个 MainWindow 和一个 Dialog 类 它是 MainWindow 类的一部分 self loginDialog LoginDialog 我使用插槽和信号 这
  • 插入多行并返回主键时 Sqlalchemy 的奇怪行为

    插入多行并返回主键时 我注意到一些奇怪的事情 如果我在 isert 查询中添加使用参数值 我会得到预期的行为 但是当将值传递给游标时 不会返回任何内容 这可能是一个错误还是我误解了什么 我的sqlachemy版本是0 9 4 下面如何重现错
  • python 类的属性不在 __init__ 中

    我想知道为什么下面的代码有效 usr bin env python3 import sys class Car def init self pass if name main c Car c speed 3 c time 5 print c
  • 计算 for 循环期间的运行总计 - Python

    编辑 下面是我根据收到的反馈 答案编写的工作代码 这个问题源于我之前使用 MIT 的开放课件学习 Python CS 时提出的问题 在这里查看我之前的问题 https stackoverflow com questions 4990159
  • 使用 shell=True 将 PATH 设置为 bitbake 的“source”在 Python 中没有效果

    下面是shell脚本中的代码 source proj common tools repo etc profile d repo sh repo project init branch repo project sync source pok
  • 如何对嵌套函数进行单元测试? [复制]

    这个问题在这里已经有答案了 您将如何对嵌套函数进行单元测试f1 在下面的例子中 def f def f1 return 1 return 2 或者需要测试的函数不应该嵌套吗 有一个类似的问题这个链接 https stackoverflow
  • 替换 pandas 数据框中的点

    我有一个如图所示的数据框 数字实际上是对象 正在做df treasury rate pd to numeric df treasury rate 可预见的炸弹 然而 做df replace np nan 似乎没有摆脱这个点 所以我很困惑 有
  • 使用 python 写入 aws lambda 中的 /tmp 目录

    Goal 我正在尝试将 zip 文件写入 python aws lambda 中的 tmp 文件夹 因此我可以在压缩之前提取操作 并将其放入 s3 存储桶中 Problem 操作系统 Errno30 只读文件系统 这段代码在我的计算机上进行
  • 如何在 Python 中包含 PHP 脚本?

    我有一个 PHP 脚本 news generator php 当我包含它时 它会抓取一堆新闻项并打印它们 现在 我在我的网站 CGI 中使用 Python 当我使用 PHP 时 我在 新闻 页面上使用了这样的内容 为了简单起见 我删掉了这个
  • Python:如何使用生成器来避免 sql 内存问题

    我有以下方法来访问 mysql 数据库 并且查询在服务器中执行 我无权更改有关增加内存的任何内容 我对生成器很陌生 并开始阅读更多有关它的内容 并认为我可以将其转换为使用生成器 def getUNames self globalUserQu
  • Python写入dbf数据时出错

    我得到这个错误 DbfError unable to modify fields individually except in with or Process 如何修复它 这是我的code with dbf Table aa dbf as
  • 找到图像特征宽度的正确方法和Python包

    输入是一个在黑色背景上带有彩色 抱歉 垂直线的光谱 给定该带的近似 x 坐标 用 X 标记 我想找到该带的宽度 我对图像处理不熟悉 请引导我前往正确的方法图像处理和Python图像处理package也能起到同样的作用 我认为 PIL Ope
  • 如何在 Flask 中获取 POSTed JSON?

    我正在尝试使用 Flask 构建一个简单的 API 现在我想在其中读取一些 POSTed JSON 我使用 Postman Chrome 扩展进行 POST 我 POST 的 JSON 很简单 text lalala 我尝试使用以下方法读取
  • 为什么《Scala 中的函数式编程》一书的“无异常处理错误”一章中没有提到“scala.util.Try”?

    在 Scala 中的函数式编程 一书中的 无异常处理错误 一章中 作者给出 从函数体抛出异常的问题 Use Option如果我们不关心实际的异常 Use Either如果我们关心实际的异常 But scala util Try没有提到 从我
  • 使用多行选项和编码选项读取 CSV

    在 azure Databricks 中 当我使用以下命令读取 CSV 文件时multiline true and encoding SJIS 似乎编码选项被忽略了 如果我使用multiline选项 Spark 使用默认值encoding那
  • 磁盘寻道时间测量方法

    我编写了一个脚本来测量 HDD 上的寻道时间 并且其完成方式的微小变化会导致显着不同的时间 第一个周期在磁盘开头的区域内进行跳转 第二个周期选择磁盘上执行查找的随机区域 相同大小 这种方法显然不同 但我不明白为什么它会改变结果 请注意 对于
  • 从 xgb.train() 获取概率

    我是 Python 和机器学习的新手 我在网上搜索了我的问题 并尝试了人们建议的解决方案 但仍然没有得到它 如果有人能帮助我 我将非常感激 我正在开发我的第一个 XGboost 模型 我已经使用 xgb XGBClassifier 调整了参

随机推荐

  • Java EE 6 CDI 事件是事务性的吗?

    Java EE 6 CDI 事件是事务性的吗 如果我在事务中触发事件 然后回滚该事务 事件侦听器的效果是否也会回滚 此行为是否依赖于事件侦听器本身支持事务 如果我尝试从事件侦听器内回滚异常 它会回滚触发该事件的事务吗 来自事件章节 http
  • spring-data-neo4j 基本一对多关系不持久

    EDIT 示例项目可在github https github com troig neo4jCustomRepository 我在后端项目中使用 Neo4J Rest 图形数据库 托管在 grapheneDb 中 和 Spring Data
  • Eclipse 调试“未找到源”

    我刚刚开始使用 Eclipse 所以慢慢来吧 但是 当尝试调试 JUnit 测试用例时 我会收到一个对话框 指出当我在测试方法中的代码中找到此行时 未找到源代码 Assert assertEquals 1 contents size 我知道
  • 改变点的边缘方向

    我正在尝试用点画一个非常简单的图表 digraph untitled rankdir LR rank same S A B gt A B gt S A gt A S gt S A gt S S gt A A gt T S gt T 我得到的
  • 将相同的多个对象推送到多个数组中

    这是后续使3个数组相互对应 第一个是对象名称 https stackoverflow com questions 57564488 make 3 arrays correspond to each other with the first
  • 如何在 WordPress 中设置发布日期的格式?

    我有一个侧边栏 我想在其中显示最新的帖子 现在它显示标题 日期和摘录 日期显示了我想要删除的时间 我用这个显示日期 recent post date
  • 如何避免多系列折线图d3.js的工具提示重叠

    我已经在多系列折线图上创建了工具提示 如下所示在这里回答 https stackoverflow com questions 34886070 d3 js multiseries line chart with mouseover tool
  • 在 R 中,如何获得某些向量值的所有可能组合?

    背景 我有一个需要一些参数的函数 我想要获得所有可能的参数组合的函数结果 一个简化的例子 f lt function x y return paste x y sep colors c red green blue days c Monda
  • h264 参考帧

    我正在寻找一种在 h264 流中查找参考帧的算法 我在不同的解决方案中看到的最常见的方法是查找访问单元分隔符和 IDR 类型的 NAL 不幸的是 我检查的大多数流没有 IDR 类型的 NAL 我将不胜感激的帮助 问候 雅采克 H264 帧由
  • 如何在 Kotlin 中强制执行空的非空字符串?

    我经常想保存一个不能为空的字符串or blank 空白不够好 编译器处理String 很好地防止 null 我们可以使用aNullableString isNullOrBlank 检查它是否为空或空白 但是 这要求在使用空白支票的所有地方都
  • 在覆盖 UIView 的右下角创建四分之一透明孔

    您好 我想在覆盖 UIView 的右下角创建一个四分之一透明孔 我可以使用下面的代码解决它 但它看起来不正确 因为我在视图之外创建了一个矩形 我尝试过的 implementation PartialTransparentView id in
  • Visual Studio 复制资源 .cs 文件

    Visual Studio 已经开始表现出一个相当令人恼火的怪癖 当我编辑资源文件 使用设计器视图或直接编辑 XML 时 它会创建重复的资源 Designer cs 文件 这会导致项目无法构建 示例 假设我的资源文件名为 ProjectSQ
  • 无效的数组分配

    我不知道我将地址分配给其他二维数组的问题出在哪里 请帮我解决这个问题 int main int a 3 2 int b 2 0 1 a 2 b return 0 prog cpp 8 9 error invalid array assign
  • 如何生成源代码来创建我正在调试的对象?

    我的典型场景 我处理的遗留代码有一个错误 只有生产中的客户端才会遇到 我附加了一个调试器并找出如何重现该问题their系统给定their输入 但是 我还不知道为什么会发生错误 现在我想在本地系统上编写一个自动化测试来尝试重现然后修复错误 最
  • 如何在Python中按字母顺序对字符串中的字母进行排序

    有没有一种简单的方法可以在Python中按字母顺序对字符串中的字母进行排序 So for a ZENOVW 我想返回 ENOVWZ 你可以做 gt gt gt a ZENOVW gt gt gt join sorted a ENOVWZ
  • 如何从 PyEphem 获取物体的地球惯性或地心坐标?

    我想获得各种物体的坐标XYZ坐标 而不是它们出现在天空中的位置 我对 感兴趣 ECE 以地心为中心 惯性 https en wikipedia org wiki Earth centered inertial 不随地球自转 ECEF 以地心
  • 如何找到 AS3 中 xml 子级的数量

    所以现场文档说这是在 XML 对象上调用 length 对于 XML 对象 此方法始终 返回整数 1 length XMLList 类的方法返回一个 对于 XMLList 对象 值为 1 仅包含一个值 我在 xml 上调用它 如下所示
  • 什么是 .un~ 文件或者为什么终端中的 Vim 会创建 .un~ 文件?

    我注意到我有一些以 un 例如我有一个 vividchalk vim un 但我不确定它是从哪里来的 看起来它们是我在终端中使用 Vim 时创建的 这些文件是什么 当我关闭正在编辑的文件时 可以让它们自行删除吗 当你编辑和保存文件时 Vim
  • Scrapy仅抓取网站的一部分

    您好 我有以下代码来扫描给定站点中的所有链接 from scrapy item import Field Item from scrapy contrib spiders import CrawlSpider Rule from scrap
  • Python abc 模块:扩展抽象基类和异常派生类会导致令人惊讶的行为

    扩展抽象基类和从 对象 派生的类可以按照您的预期工作 如果您尚未实现所有抽象方法和属性 则会出现错误 奇怪的是 用扩展 Exception 的类替换对象派生类允许您创建不实现所有必需的抽象方法和属性的类的实例 例如 import abc T