Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python __子类或通过uuu初始化uu子类uuuuu注册?_Python_Python 3.x_Metaclass - Fatal编程技术网

Python __子类或通过uuu初始化uu子类uuuuu注册?

Python __子类或通过uuu初始化uu子类uuuuu注册?,python,python-3.x,metaclass,Python,Python 3.x,Metaclass,假设我想创建某个类的子类的注册表。现在我可以想到两种方法,虽然我知道它们之间的一些差异,但我很想了解更多关于这个主题的内容 class Base: pass class DerivedA(Base): pass class DerivedB(Base): pass __子类__ 如果我有上述情况,我可以简单地得到Base的子类列表,如下所示: >>> [cmd.__name__ for cmd in Base.__subclasses__()] [

假设我想创建某个类的子类的注册表。现在我可以想到两种方法,虽然我知道它们之间的一些差异,但我很想了解更多关于这个主题的内容

class Base:
    pass

class DerivedA(Base):
    pass

class DerivedB(Base):
    pass
__子类__ 如果我有上述情况,我可以简单地得到Base的子类列表,如下所示:

>>> [cmd.__name__ for cmd in Base.__subclasses__()]
['DerivedA', 'DerivedB']
class DerivedC(DerivedA):
    pass
现在我知道,如果我添加了第三个类,而不是像这样直接子类化基:

>>> [cmd.__name__ for cmd in Base.__subclasses__()]
['DerivedA', 'DerivedB']
class DerivedC(DerivedA):
    pass
我不会在列表中看到这个:

>>> [cmd.__name__ for cmd in Base.__subclasses__()]
['DerivedA', 'DerivedB']
此外,我不能过滤子类,例如,出于任何原因忽略某个特定的子类

__init_子类__ 由于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
然后只需访问_注册表:

如果需要,我还可以修改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
为什么要使用后者? 现在让我们假设我不想过滤子类,我只对直接子类感兴趣。我知道,前一种方法似乎更简单,更主观。其他的区别是什么?后一种方法的优势是什么


谢谢

在这种情况下,在基类中编写_init_subclass_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu的明显好处是

如果您只需要直接从基继承的类,那么它就可以在_子类_方法中使用,主要的优点是您不需要编写一行代码,甚至不需要保留单独的注册表,因为_子类_将为您这样做

但是,除非您正在编写一个相对较小的应用程序,或者正在处理一个只需要查找少量固定数量的这些子类的功能,否则依赖_子类是不够的-如果您只是需要或想要层次结构中的另一个级别的类,它将停止工作,无论如何,你必须求助于真正的注册中心

在使用_init_子类__钩子之前,您必须编写一个适当的元类来保存此注册表,将其提供给元类_init__方法,或者执行一个复杂的递归查询,如:

def check_子类库,候选项: 对于基本类中的cls。子类: 如果cls是候选人: 返回真值 如果检查子条款,候选人: 返回真值 返回错误 而且,尽管应该不用说,_init_subclass_uu方法可以做的远不止保持一个注册表,因为它可以运行任何代码。它可以对照DB层检查映射到该子类的字段是否是最新的,并警告需要进行的迁移,甚至可以执行DB迁移本身,或者初始化创建类实例时需要找到的任何资源,如记录器处理程序、线程池、DB连接池等等


TL;DR:如果你只需要一个类的直接子类,那就使用_子类。关键在于它只是注释了直接子类。

我不确定这是否是一个关于堆栈溢出的有效问题。更好的方法是非常主观的,你已经在问题中描述了不同类别之间的大部分差异,所以在回答问题时,我们所能做的就是宣泄我们的观点。也许,如果你解释了为什么你想要一个类名列表,外界会更容易理解你的目标是什么,以及这两种可能的解决方案将如何帮助你实现目标,但如果没有这两种解决方案,我们只是猜测,或争论涂自行车棚的颜色。你想比较什么,定义registry的两种方法,或者是定义uu子类的uu registry方法?仅仅因为更新的uuu init_子类uuu可用于重新实现uuu子类uuuuu并不意味着这样做有任何好处。也许dupe:这里提到的两个选项都已经在这里详细讨论过了。此外,听起来你对这两种方法都非常了解,所以不确定你在寻找什么样的答案。注意_子类_可以非常简单地进行递归。你们是对的,我对这个问题做了一些编辑。你很好地理解和描述了这两个概念及其差异,没有其他显著差异。随便挑感觉好点的。这对我来说是个好答案。我想知道我是否忽略了什么。谢谢