python subclasscheck和subclasshook

python subclasscheck和subclasshook,第1张

python subclasscheck和subclasshook

两种方法均可用于自定义

issubclass()
内置函数的结果。

__subclasscheck__

class.__subclasscheck__(self, subclass)

如果子类应被视为类的(直接或间接)子类,则返回true。如果定义,则调用实现

issubclass(subclass, class)

请注意,这些方法是在类的类型(元类)上查找的。它们不能定义为实际类中的类方法。这与在实例上调用的特殊方法的查找一致,仅在这种情况下,实例本身是一个类。

此方法是负责

issubclass
检查定制的特殊方法。就像“注释”中所述,它必须在元类上实现!

class YouWontFindSubclasses(type):    def __subclasscheck__(cls, subclass):        print(cls, subclass)        return Falseclass MyCls(metaclass=YouWontFindSubclasses):    passclass MySubCls(MyCls):    pass

即使您拥有真正的子类,此实现也会返回False:

>>> issubclass(MySubCls, MyCls)<class '__main__.MyCls'> <class '__main__.MySubCls'>False

实际上,

__subclasscheck__
实现还有更多有趣的用途。例如:

class SpecialSubs(type):    def __subclasscheck__(cls, subclass):        required_attrs = getattr(cls, '_required_attrs', [])        for attr in required_attrs: if any(attr in sub.__dict__ for sub in subclass.__mro__):     continue return False        return Trueclass MyCls(metaclass=SpecialSubs):    _required_attrs = ['__len__', '__iter__']

有了这个实现的任何类,定义

__len__
__iter__
返回
True
issubclass
检查:

>>> issubclass(int, MyCls)  # ints have no __len__ or __iter__False>>> issubclass(list, MyCls)  # but lists and dicts haveTrue>>> issubclass(dict, MyCls)True

在这些示例中,我没有调用超类

__subclasscheck__
,因此禁用了正常
issubclass
行为(由实现
type.__subclasscheck__
)。但是重要的是要知道,您还可以选择只是
扩展 正常行为,而不是完全覆盖它:

class meta(type):    def __subclasscheck__(cls, subclass):        """Just modify the behavior for classes that aren't genuine subclasses."""        if super().__subclasscheck__(subclass): return True        else: # Not a normal subclass, implement some customization here.

__subclasshook__

__subclasshook__(subclass)

(必须定义为类方法。)

检查子类是否被视为此ABC的子类。这意味着您可以自定义

issubclass
进一步的行为,而无需调用
register()
要考虑为ABC的子类的每个类。(此类方法是从
__subclasscheck__()
ABC的方法中调用的。)

这个方法应该返回

True
False
NotImplemented
。如果返回
True
,则将该子类视为此ABC的子类。如果返回
False
,则即使该子类通常是一个子类,也不会将该子类视为该ABC的子类。如果返回
NotImplemented
,则使用常规机制继续子类检查。

这里重要的一点是,它是

classmethod
在类上定义的,并由调用
abc.ABC.__subclasscheck__
。因此,只有在处理具有
ABCmeta
元类的类时才可以使用它:

import abcclass MyClsABC(abc.ABC):    @classmethod    def __subclasshook__(cls, subclass):        print('in subclasshook')        return Trueclass MyClsNoABC(object):    @classmethod    def __subclasshook__(cls, subclass):        print('in subclasshook')        return True

这只会进入

__subclasshook__
第一个:

>>> issubclass(int, MyClsABC)in subclasshookTrue>>> issubclass(int, MyClsNoABC)False

请注意,后续的

issubclass
调用不会再进入
__subclasshook__
,因为会
ABCmeta
缓存结果:

>>> issubclass(int, MyClsABC)True

请注意,通常检查第一个参数是否是类本身。这是为了避免子类“继承”,

__subclasshook__
而不是使用常规子类确定。

例如(来自CPython

collections.abc
模块):

from abc import ABCmeta, abstractmethoddef _check_methods(C, *methods):    mro = C.__mro__    for method in methods:        for B in mro: if method in B.__dict__:     if B.__dict__[method] is None:         return NotImplemented     break        else: return NotImplemented    return Trueclass Hashable(metaclass=ABCmeta):    __slots__ = ()    @abstractmethod    def __hash__(self):        return 0    @classmethod    def __subclasshook__(cls, C):        if cls is Hashable: return _check_methods(C, "__hash__")        return NotImplemented

因此,如果您检查某物是否是其子类,

Hashable
则将使用由
__subclasshook__
守护的自定义实现
if cls isHashable
。但是,如果您有一个实际的类来实现该
Hashable
接口,则您不希望它继承该
__subclasshook__
机制,而是希望使用普通的子类机制。

例如:

class MyHashable(Hashable):    def __hash__(self):        return 10>>> issubclass(int, MyHashable)False

即使

int
实现
__hash__
__subclasshook__
检查
__hash__
实现,这种情况下的结果也是
False
。它仍然输入
__subclasshook__
of,
Hashable
但是它立即返回使用正常实现应继续进行处理的
NotImplemented
信号
ABCmeta
。如果没有,
ifcls is Hashable
issubclass(int, MyHashable)
返回
True

当你应该使用
__subclasscheck__
以及何时
__subclasshook__

真的要看

__subclasshook__
可以在类上而不是在元类上实现,但要求您使用
ABCmeta
(或的子类
ABCmeta
)作为元类,因为该
__subclasshook__
方法实际上只是Pythons
abc
模块引入的约定。

您可以随时使用,

__subclasscheck__
但必须在元类上实现。

在实践中,

__subclasshook__
如果要实现接口(因为这些接口通常使用
abc
)并且要自定义子类机制,则使用。而你使用
__subclasscheck__
,如果你想创造自己的约定(如
abc
没有)。因此,在99.99%的正常(不好玩)情况下,您只需要
__subclasshook__



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5566083.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存