微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决每个 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 举报,一经查实,本站将立刻删除。