blu*_*ote 24 python python-3.x
方法__subclasscheck__和__subclasshook__用于确定一个类是否被视为另一个类的子类.但是,他们的文档非常有限,即使在高级python书籍中也是如此.它们是如何被使用的,它们的区别是什么(更高的优先级,它们所指的关系的一面......等等)
MSe*_*ert 32
这两种方法都可用于自定义issubclass()内置函数的结果.
__subclasscheck__
class.__subclasscheck__(self, subclass)如果子类应被视为类的(直接或间接)子类,则返回true.如果定义,则调用实现
issubclass(subclass, class).请注意,这些方法是在类的类型(元类)上查找的.它们不能在实际类中定义为类方法.这与在实例上调用的特殊方法的查找一致,只是在这种情况下,实例本身就是一个类.
此方法是负责自定义issubclass检查的特殊方法.就像"Note"状态一样,它必须在元类上实现!
class YouWontFindSubclasses(type):
def __subclasscheck__(cls, subclass):
print(cls, subclass)
return False
class MyCls(metaclass=YouWontFindSubclasses):
pass
class MySubCls(MyCls):
pass
Run Code Online (Sandbox Code Playgroud)
即使您有真正的子类,此实现也将返回False:
>>> issubclass(MySubCls, MyCls)
<class '__main__.MyCls'> <class '__main__.MySubCls'>
False
Run Code Online (Sandbox Code Playgroud)
实际上有更多有趣的用途__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 True
class MyCls(metaclass=SpecialSubs):
_required_attrs = ['__len__', '__iter__']
Run Code Online (Sandbox Code Playgroud)
通过此实现,任何定义__len__并将在检查中__iter__返回的类:Trueissubclass
>>> issubclass(int, MyCls) # ints have no __len__ or __iter__
False
>>> issubclass(list, MyCls) # but lists and dicts have
True
>>> issubclass(dict, MyCls)
True
Run Code Online (Sandbox Code Playgroud)
在这些示例中,我没有调用超类__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.
Run Code Online (Sandbox Code Playgroud)
__subclasshook__
__subclasshook__(subclass)(必须定义为类方法.)
检查子类是否被视为此ABC的子类.这意味着您可以
issubclass进一步自定义行为,而无需调用register()要考虑ABC子类的每个类.(这个类方法是从__subclasscheck__()ABC 的方法调用的.)这个方法应该返回
True,False或者NotImplemented.如果它返回True,则子类被视为该ABC的子类.如果它返回False,则子类不被视为该ABC的子类,即使它通常是一个.如果它返回NotImplemented,则使用通常的机制继续子类检查.
这里重要的一点是,它被定义为classmethod类,并且它被调用abc.ABC.__subclasscheck__.因此,如果您正在处理具有ABCMeta元类的类,则只能使用它:
import abc
class MyClsABC(abc.ABC):
@classmethod
def __subclasshook__(cls, subclass):
print('in subclasshook')
return True
class MyClsNoABC(object):
@classmethod
def __subclasshook__(cls, subclass):
print('in subclasshook')
return True
Run Code Online (Sandbox Code Playgroud)
这只会进入__subclasshook__第一个:
>>> issubclass(int, MyClsABC)
in subclasshook
True
>>> issubclass(int, MyClsNoABC)
False
Run Code Online (Sandbox Code Playgroud)
请注意,后续issubclass调用不再进入__subclasshook__,因为ABCMeta缓存结果:
>>> issubclass(int, MyClsABC)
True
Run Code Online (Sandbox Code Playgroud)
请注意,您通常会检查第一个参数是否为类本身.这是为了避免子类"继承" __subclasshook__而不是使用正常的子类确定.
例如(来自CPython collections.abc模块):
from abc import ABCMeta, abstractmethod
def _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 True
class 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
Run Code Online (Sandbox Code Playgroud)
因此,如果你检查某些东西是否是Hashable它的子类,它将使用由__subclasshook__守护的自定义实现if cls is Hashable.但是,如果您有实现该Hashable接口的实际类,则不希望它继承该__subclasshook__机制,但您需要正常的子类机制.
例如:
class MyHashable(Hashable):
def __hash__(self):
return 10
>>> issubclass(int, MyHashable)
False
Run Code Online (Sandbox Code Playgroud)
即使int实现__hash__和__subclasshook__检查__hash__实现,在这种情况下的结果是False.它仍然进入__subclasshook__,Hashable但它立即返回NotImplemented哪些信号ABCMeta应该使用正常实现继续.如果它没有if cls is Hashable那么issubclass(int, MyHashable)就会回来True!
__subclasscheck__何时__subclasshook__?这真的取决于.__subclasshook__可以在类而不是元类上实现,但要求您使用ABCMeta(或子类ABCMeta)作为元类,因为该__subclasshook__方法实际上只是Pythons abc模块引入的约定.
您可以随时使用,__subclasscheck__但必须在元类上实现.
在实践中,__subclasshook__如果您实现接口(因为这些通常使用abc)并且想要自定义子类机制,则使用它.__subclasscheck__如果你想发明自己的约定(比如abc做),你可以使用它.因此,您只需要99.99%的正常(不好玩)案例__subclasshook__.
小智 6
__subclasshook__并__subclasscheck__用于自定义issubclass函数的行为.abc源代码中的更多信息.
__subclasscheck__查找类的类型(元类).它不应该为普通类定义.
__subclasshook__检查子类是否被视为某些ABC的子类.这意味着您可以issubclass进一步自定义行为,而无需在要考虑ABC子类的每个类上调用register().
这意味着您可以__subclasshook__在ABC类中定义一些条件,并且满足该条件的所有类都将作为子类考虑.
例如:
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(object):
pass
class B(object):
def __len__(self):
return 0
issubclass(A, Sized) # False
issubclass(B, Sized) # True
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6310 次 |
| 最近记录: |