每个 ABC 文档的 python inspect.isabstract 结果不正确

问题描述

似乎只有当两个 inspect.isabstract AND Metaclass 都存在时,@abstractmethod 才会返回 true。但这不是医生所说的,至少在我读到它的时候——更重要的是,我根本不相信它是最不令人惊讶的。我需要这个正确/错误吗?

这个类的评估结果与预期的一样抽象

class Both(ABC):
    isabstract_result = True

    @abstractmethod
    def foo(self):
        pass

isabstract() 的结果在这里 既不符合文档也不符合常见用法 https://docs.python.org/3/library/abc.html

class JustABC(ABC):
    # docs: "an abstract base class can be created by simply deriving from ABC"
    isabstract_result = False

我认为这里的技术论点是,为了使派生类变得具体,它们需要实现一个(以前是 abstractmethod方法;因此,通过归纳,在其 mro 中没有这种方法的基类不能是 abstract - 但恕我直言,这将是一个文档错误修复需要,因为它似乎并不是最不令人惊讶的,尤其是考虑到明确的措辞就像今天一样。

这是显示上述内容的可运行代码(以及上述内容的其他一些结果)。在 pythong 3.8.5(认为 ubuntu 20.04)上运行时,unittest.Testcase 通过

from unittest import TestCase
from abc import abstractmethod,ABC
from inspect import isabstract

# these classes evaluate as abstract as expected
class Both(ABC):
    isabstract_result = True

    @abstractmethod
    def foo(self):
        pass


# the result of isabstract() here
# is consistent with neither the docs nor common usage
# https://docs.python.org/3/library/abc.html
class JustABC(ABC):
    # docs: "an abstract base class can be created by simply deriving from ABC"
    isabstract_result = False


# that this code loads without error would seem to be inconsistent with the docs
# although admittedly nothing about "required" implies there is any error checking
class JustABm:
    isabstract_result = False
    # docs: Using this decorator requires that the class [...] or is derived from [ABC]"
    @abstractmethod
    def foo(self):
        pass


# for reference,trivial derrived classes preserve the above
class ChildBoth(Both):
    isabstract_result = True


class ChildJustABm(JustABC):
    isabstract_result = False


class ChildJustABC(JustABm,ABC):
    isabstract_result = False


# and there is asymitry about adding the other abc notion;
# although this probably makes sense given the implementation & inheritance
class ChildAddABm(JustABC):
    isabstract_result = True

    @abstractmethod
    def foo(self):
        pass


class ChildAddABC(JustABm,ABC):
    isabstract_result = False


CLASSES = (
    JustABC,JustABm,Both,ChildJustABC,ChildJustABm,ChildBoth,ChildAddABm,ChildAddABC,)


class test_isabstract(TestCase):
    """ verify the flags above: test passes """

    def test_isabstract(self):

        for cls,status in zip(CLASSES,map(isabstract,CLASSES)):
            self.assertEqual(
                cls.isabstract_result,status,f"error,{cls.__name__ = } {'IS' if status else 'is NOT'} abs,which is not expected.",)

    def test_runtime_matches_isabstract(self):
        # at least the actual runtime behavior is consistent with inspect.isabstract
        for cls in CLASSES:
            try:
                cls()
                self.assertFalse(
                    cls.isabstract_result,f"{cls} instantiated,but should have Failed as ABC",)
            except TypeError as _ex:
                self.assertTrue(
                    cls.isabstract_result,f"{cls} Failed to instantiate as abc unexpectedly",)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)