测试类型与 issubclass returns 不一致的结果

Testing types with issubclass returns inconsistent results

我有一个 class A 没有属性,我测试它是否是 typing.Container 的子类。正如预期的那样,该测试失败了。

在单独的测试中,我将 __contains(self, k)__ 属性添加到 A,并测试它是否是 typing.Container 的子类,并且测试通过。

现在奇怪的是,如果我测试 A 是否是 typing.Conainer 的子类,然后添加 __contains(self, k)__ 属性,然后再次测试 A 是否是 typing.Container 的子类,该测试失败。

发生了什么导致最后一个测试失败,即使 A 确实具有属性 __contains__(self, k)__?

import pytest
from typing import Container

@pytest.fixture
def A():
    class A:...
    return A

def test_notsubclass(A):
    # passes
    assert not issubclass(A, Container)

def test_addcontains(A):
    # passes
    def __contains__(self, k): ...
    setattr(A, '__contains__', __contains__)
    assert issubclass(A, Container)

def test_first_then_add_contains(A):
    # passes
    assert not issubclass(A, Container)
    def __contains__(self, k): ...
    setattr(A, '__contains__', __contains__)

    # fails
    assert issubclass(A, Container)

许多 typing 类型的运行时表示是相应 collections.abc 类型的包装器。 For example, typing.Container is a generic "alias" of collections.abc.Container:

Container = _alias(collections.abc.Container, 1)

顾名思义,collections.abc 成员派生自 abc.ABC/abc.ABCMeta。由于 ABC subclass/instance 检查可能很昂贵,abc.ABCMeta has an optimisation to cache subclass checks.