两种方法均可用于自定义
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__。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)