为什么 abc.ABCMeta 抽象实例化检查不能对“list”和“dict”的派生进行检查?

2024-06-09

我一直在尝试一些abcpython 中的模块。阿拉

>>> import abc

在正常情况下,如果 ABC 类包含未实现的类,则您希望它不会被实例化abstractmethod。你知道如下:

>>> class MyClass(metaclass=abc.ABCMeta):
...     @abc.abstractmethod
...     def mymethod(self):
...         return -1
...
>>> MyClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyClass with abstract methods mymethod

OR 对于任何派生类。一切似乎都工作正常,直到你继承了某些东西......说dict or list如下:

>>> class YourClass(list, metaclass=abc.ABCMeta):
...     @abc.abstractmethod
...     def yourmethod(self):
...         return -1
...
>>> YourClass()
[]

这很令人惊讶,因为type无论如何,这可能是主要工厂或元类的东西,所以我从以下内容中假设。

>>> type(abc.ABCMeta)
<class 'type'>
>>> type(list)
<class 'type'>

通过一些调查,我发现它可以归结为简单的事情,比如添加一个__abstractmethod__类的属性'object休息自然发生:

>>> class AbstractClass:
...     pass
...
>>> AbstractClass.__abstractmethods__ = {'abstractmethod'}
>>> AbstractClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class AbstractClass with abstract methods abstractmethod

因此,人们可以通过故意覆盖来避免检查__new__方法及清理__abstractmethods__如下:

>>> class SupposedlyAbstractClass(metaclass=abc.ABCMeta):
...     def __new__(cls):
...         cls.__abstractmethods__ = {}
...         return super(AbstractClass, cls).__new__(cls)
...     @abc.abstractmethod
...     def abstractmethod(self):
...         return -1
...
>>> SupposedlyAbstractClass()
<__main__.SupposedlyAbstractClass object at 0x000001FA6BF05828>

正如我亲自检查过的,这种行为在 Python 2.7 和 Python 3.7 中是相同的。我不知道这对于所有其他 python 实现是否相同。

最后,回到问题......为什么会这样?我们永远不应该用抽象类来创建抽象类是明智的吗?list, tuple or dict?或者我应该继续添加一个__new__类方法检查__abstractmethods__在实例化之前?


问题

如果你还有下一堂课:

from abc import ABC, abstractmethod
class Foo(list, ABC):
    @abstractmethod
    def yourmethod(self):
        pass

问题在于Foo can创建时没有任何错误,因为Foo.__new__(Foo)将呼叫直接委托给list.__new__(Foo)代替ABC.__new__(Foo)(负责检查所有抽象方法是否在要实例化的类中实现)

我们可以实施__new__在 Foo 上并尝试调用ABC.__new__:

class Foo(list, ABC):
    def __new__(cls, *args, **kwargs):
        return ABC.__new__(cls)

    @abstractmethod
    def yourmethod(self):
        pass
Foo()

但他提出了下一个错误:

TypeError: object.__new__(Foo) is not safe, use list.__new__()

这是因为ABC.__new__(Foo)调用object.__new__(Foo)这似乎是不允许的Foo继承自list

一个可能的解决方案

您可以添加额外的代码Foo.__new__为了检查要实例化的类中的所有抽象方法是否都已实现(基本上完成以下工作ABC.__new__).

像这样的事情:

class Foo(list, ABC):
    def __new__(cls, *args, **kwargs):
        if hasattr(cls, '__abstractmethods__') and len(cls.__abstractmethods__) > 0:
            raise TypeError(f"Can't instantiate abstract class {cls.__name__} with abstract methods {', '.join(cls.__abstractmethods__)}")
        return super(Foo, cls).__new__(cls)


    @abstractmethod
    def yourmethod(self):
        return -1

Now Foo()引发错误。但接下来的代码运行没有任何问题:

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

为什么 abc.ABCMeta 抽象实例化检查不能对“list”和“dict”的派生进行检查? 的相关文章

随机推荐

  • sed:多行的条件合并

    我需要根据模式使用 sed 合并文件行 例如 输入文件 X1 A B C D E F G H I J 1 LK T PP E OO 2 X2 DDF F Y J W Q 预期输出 X1 A B C D E F G H I J 1 LK T
  • Rails 会话间歇性重置

    我知道这个主题已经被讨论了很多 但我相信我已经找到了它的一个新变体 我有一个 Rails 4 应用程序 它是从 Rails 3 升级的 并且具有rails ujs and csrf meta tags设置正确 一旦root url在浏览器中
  • 将以utf-8字符串为内容的unicode转换为str

    我正在使用 pyquery 来解析页面 dom PyQuery http zh wikipedia org w index php title CSS printable yes variant zh cn content dom mw c
  • 如何清除 tf.flags?

    如果我运行此代码两次 tf flags DEFINE integer batch size 2 batch size for training 我会得到这个错误 DuplicateFlagError The flag batch size
  • 如何在 Vim 中特定列的所有行中插入特定字符?

    Dates Name Date Battle of the Plains of Abraham September 13 1759 Proclamation Act October 07 1763 Stamp Act March 22 17
  • 将某人的当地时间转换为 UTC 时间

    我有点迷失在时区中 我存储了 UTC 时间的数据 服务器位于荷兰 所以我们生活在 utc 1 现在采用夏令时 采用 utc 2 现在客户说 给我8月5日的数据 所以我必须从 他的时间 计算UTC时间 为此我必须知道 你的 utc 偏移量是多
  • VS2010、HTML 5 和 CSS 3 验证

    我想将 VS2010 SP1 中的 CSS 验证从 CSS 2 1 切换到 CSS 3 我遇到了这个答案 VS2010中是否可以更改CSS验证方案 https stackoverflow com questions 3931801 is i
  • 在 if-else 语句中使用标签和中断

    我有这段代码 它在特定条件下 当 x 和 y 都等于零时 从数组生成随机数 我想让控件跳转到标签 但该控件在任何情况下都不会跳转到标签 我想知道我这样做是否正确 int arr 0 1 2 Random rn new Random labe
  • 如何在 Chart.js 中从最高到最低对数据进行排序

    我在如何使用 Chart js 对数据从高到低进行排序时遇到一些问题 我使用 Laravel 并使用 Chart js 来显示我的数据 但是我不知道如何进行操作以将 Chart js 中的最高值排序为最低值 数据 My code var c
  • 是什么导致我的运行时间比用户时间长得多?

    我正在对一些 R 语句进行基准测试 查看详细信息here https stackoverflow com questions 13685295 descending sort in data table and speed 并发现我的运行时
  • Google FCM 服务器:200 但未向手机发送通知

    我正在通过 Postman 将 FCM 推送通知发送到已安装该应用程序的手机 我启用了推送通知 应用程序位于后台 并且我有一个有效的 已确认的 Firebase 推送令牌 我正在发帖到https fcm googleapis com fcm
  • Jetpack compose 破坏了 Room 编译器

    我使用 Android Studio 4 0 Canary 6 创建了一个全新的 jetpack compose 项目 从项目模板 并尝试添加房间依赖项 这是我的应用程序级别build gradle apply plugin com and
  • 如何从 8 位中取出第 3 位

    我有这个十六进制 08这是二进制的 0000 1000 位位置 7 6 5 4 3 2 1 0 现在我想在 python 中创建一个位掩码 所以我有位位置 3 这里以示例为例1或更好 中的那个 0000 1 000 我该怎么办才只有这一点呢
  • XML-XSLT:如何比较字符串中的两个日期

    我知道这个问题可能会重复 而且我也浏览过类似的文章和问题 但我还没有找到确切的解决方案 现在问题 我在用XSLT or XPATH来转换 xml XML 中有两个字符串变量 一个是OldDate第二个是CurrentDate Ex oldD
  • 辅助角色进程能否以编程方式调用 Azure 云服务的反恶意软件?

    我正在尝试找到一种解决方案 可用于对已上传到 Azure Blob 存储的文件执行病毒扫描 我想知道是否可以将文件复制到辅助角色实例上的本地存储 调用 Azure 云服务的反恶意软件来对该特定文件执行扫描 然后根据文件是否干净 相应地处理该
  • 使用 mongoose 将非常大的 CSV 保存到 mongoDB

    我有一个包含超过 200 000 行的 CSV 文件 我需要将其保存到 MongoDB 如果我尝试 for 循环 Node 将耗尽内存 fs readFile data txt function err data if err throw
  • 检测iframe内容高度变化

    有plenty展示如何动态设置的示例iframe的高度相对于其内容 这对我来说非常适合 我现在遇到的问题是内容可以改变大小而不触发onload 认为 隐藏 可扩展divs 有什么方法可以检测到iframe内容有变化吗 这是在同一个域上 请不
  • 在 VSCode Fortran 调试中检查从另一个模块导入的变量

    我正在调试一些包含许多 Fortran 模块的代码 其中一些模块彼此共享变量 不幸的是 带有 VScode 的 gdb 在调试时似乎无法检查导入的变量 目前 当我需要检查导入的变量时 唯一的方法是停止调试 并手动更改代码以包含等于导入变量的
  • 如何计算目录的 git 哈希对象?

    有人有在目录上使用 git hash object 的示例吗 它在文件上很容易工作 但在目录上却不能像我期望的那样工作 git hash object c somefile txt git hash object t tree c some
  • 为什么 abc.ABCMeta 抽象实例化检查不能对“list”和“dict”的派生进行检查?

    我一直在尝试一些abcpython 中的模块 阿拉 gt gt gt import abc 在正常情况下 如果 ABC 类包含未实现的类 则您希望它不会被实例化abstractmethod 你知道如下 gt gt gt class MyCl