当类被派生时,pythonabc子类钩子不起作用

2024-10-06 07:06:43 发布

您现在位置:Python中文网/ 问答频道 /正文

当类从具有__subclashook__实现的类派生时,无法从issubclass返回False。我修改的代码来自: python subclasscheck & subclasshook 我只在两个类定义中添加了“(size)”:

from abc import ABCMeta

class Sized(metaclass=ABCMeta):
    @classmethod
    def __subclasshook__(cls, C):
        if cls is Sized:
            if any("__len__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented

class A(Sized):
    pass

class B(Sized):
    def __len__(self):
        return 0

print(issubclass(A, Sized))  # True - should be False
print(issubclass(B, Sized))  # True

在这种情况下有没有办法返回False?或者我做错了什么?在


Tags: infalsetruelenreturnifdefclass
2条回答

问题是当__subclasshook__没有提前退出时,return NotImplemented。如documentation所述:

If it returns NotImplemented, the subclass check is continued with the usual mechanism.

所以它使用正常的子类检查,发现您确实继承了Sized,因此返回True。在

有两种解决方案:

  1. return False而不是return NotImplemented。但是,您真的想要/需要issubclass直接子类返回False

  2. 如果从object继承类AB的类,它将按预期工作:

    class A(object):
        pass
    
    class B(object):
        def __len__(self):
            return 0
    
    print(issubclass(A, Sized))  # False
    print(issubclass(B, Sized))  # True
    

我认为实现这一点的好方法是:

from abc import ABCMeta

class Sized(metaclass=ABCMeta):
    @classmethod
    def __subclasshook__(cls, C):
        if cls is Sized:
            if any("__len__" in B.__dict__ for B in C.__mro__):
                return True
            else:
                return False
        return NotImplemented


class A(Sized):
    pass


class B(Sized):
    def __len__(self):
        return 0


print(issubclass(A, Sized))  # False
print(issubclass(B, Sized))  # True

我认为当我们假设abc是与其他语言中的编译(或反射)类似的机制时,我们应该返回False。如果有人怀疑这个类是正确的子类,那么代码就不应该运行,甚至不应该编译(python中没有)。在

相关问题 更多 >