假设我想创建一个特定类的子类的注册表。现在有两种方法我可以想到,虽然我知道(一些)他们的差异,我想了解更多关于这个话题。你知道吗
class Base:
pass
class DerivedA(Base):
pass
class DerivedB(Base):
pass
__subclasses__()
如果有上述情况,我可以简单地得到Base
的子类列表,如下所示:
>>> [cmd.__name__ for cmd in Base.__subclasses__()]
['DerivedA', 'DerivedB']
现在我知道,如果我添加第三个类,它不是直接子类化Base
,如下所示:
class DerivedC(DerivedA):
pass
我不会在列表中看到这个:
>>> [cmd.__name__ for cmd in Base.__subclasses__()]
['DerivedA', 'DerivedB']
我也不能过滤子类,例如忽略一个特定的子类的任何原因。你知道吗
__init_subclass__()
由于Python3.6提供了一个很好的类创建过程的钩子,不需要编写自己的元类就可以完成更高级的事情。所以我也可以这样做。。。你知道吗
_registry = []
class Base:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
_registry.append(cls.__name__)
class DerivedA(Base):
pass
class DerivedB(Base):
pass
class DerivedC(DerivedA):
pass
然后只需访问_registry
:
>>> _registry
['DerivedA', 'DerivedB', 'DerivedC']
如果需要,我还可以修改Base
以忽略某些子类:
_registry = []
class Base:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
if cls.__name__ != 'DerivedB':
_registry.append(cls.__name__)
class DerivedA(Base):
pass
class DerivedB(Base):
pass
class DerivedC(DerivedA):
pass
>>> _registry
['DerivedA', 'DerivedC']
现在假设我不想过滤子类,我只对直接子类感兴趣。前一种方法似乎更简单(我知道是主观的)。其他的区别是什么?后一种方法的优点是什么?你知道吗
谢谢!你知道吗
在本例中,在基类中编写
__init_subclass__
的明显好处是,您可以自动获得不直接从基类继承的子类。你知道吗如果您只需要直接从基继承的类,那么它就可以在
__subclasses__
方法中使用,主要的优点是您不需要编写一行代码,甚至不需要保留单独的注册表,因为__subclasses__
会为您这样做。你知道吗但是,除非您正在编写一个相对较小的应用程序,或者正在处理一个只需要查找少量固定数量的子类的功能,否则依赖
__subclasses__
是不够的—如果您只是需要或想要层次结构中的另一个级别的类,它将停止工作,而且您必须求助于真正的注册表。你知道吗在使用
__init_subclass__
钩子之前,您必须编写一个适当的元类来保留此注册表,并将其输入元类__init__
方法,或者执行一个复杂的递归查询,如:而且,尽管应该不言而喻,
__init_subclass__
方法可以做的远不止简单地保留一个注册表,因为它可以运行任何代码。它可以根据DB层检查映射到该子类的字段是否是最新的,并警告需要进行的迁移,甚至可以自己执行DB迁移,或者初始化创建类实例时需要找到的任何资源,例如记录器处理程序、线程池、DB连接池(如您所说)。你知道吗TL;DR:如果您只需要类的直接子类,请使用
__subclasses__
。关键在于它只是注释了直接子类。你知道吗相关问题 更多 >
编程相关推荐