Python3.5:使用继承进行类初始化

Python3.5:使用继承进行类初始化,python,metaprogramming,python-3.5,metaclass,Python,Metaprogramming,Python 3.5,Metaclass,我最近在Python中偶然发现了元类,并决定使用它们来简化一些特性。(使用Python 3.5) 简而言之,我正在编写一个模块,定义必须注册和初始化的类,如“组件”(我的意思是我需要初始化实际的类,而不是实例) 我可以轻松注册课程: 类元组件(类型): 定义初始值(cls,*args,**kargs): 超级() 注册表组件(cls) 类BaseComponent(元类=元组件): 通过 类组件(BaseComponent): “”“这是编写组件时要使用的实际类”“” 在本例中,我正在注册组件

我最近在Python中偶然发现了元类,并决定使用它们来简化一些特性。(使用Python 3.5)

简而言之,我正在编写一个模块,定义必须注册和初始化的类,如“组件”(我的意思是我需要初始化实际的类,而不是实例)

我可以轻松注册课程:

类元组件(类型):
定义初始值(cls,*args,**kargs):
超级()
注册表组件(cls)
类BaseComponent(元类=元组件):
通过
类组件(BaseComponent):
“”“这是编写组件时要使用的实际类”“”
在本例中,我正在注册组件的类,因为它允许我稍后引用它们,而不需要它们的实际引用

但是类缺乏自我初始化的能力(至少在Python 3.5中是这样),并且可能会导致一些问题,例如:

class Manager(Component):
    SubManagers = []

    @classmethod
    def ListSubManagers(cls):
        for manager in cls.SubManagers:
            print(manager)

    @classmethod
    def RegisterSubManager(cls, manager):
        cls.SubManagers.append(manager)
        return manager

@Manager1.RegisterSubManager
class Manager2(Manager):
    pass

@Manager2.RegisterSubManager
class Manager3(Manager):
    pass

# Now the fun:
Manager1.ListSubManagers()

# Displays:
# > Manager2
# > Manager3
现在,这是一个问题,因为我们的想法是每个经理都有一个唯一的副经理列表。但是
SubManager
字段在每个子类之间共享。。。因此,加入一个人的名单会增加每个人的。撕裂

下一个想法是实现一种初始化器:

class BaseManager(Component):
    @classmethod
    def classinit(cls):
        cls.SubManagers = []
但是现在,我需要一种在类创建之后调用这个方法的方法。让我们再次对元类执行此操作:

class MetaComponent(type):
    def __init__(cls, *args, **kargs):
        super().__init__(*args, **kargs):
        cls.classinit(**kargs)
        RegisterComponent(cls)

class BaseComponent(metaclass=MetaComponent):
    @classmethod
    def classinit(cls, **kargs):
        print('BASE', cls)

class Component(BaseComponent):
    @classmethod
    def classinit(cls, **kargs):
        super().classinit(**kargs) # Being able to use super() is the goal
        print('COMPONENT', cls)
我会考虑自己做这件事。在我看来,这是一种优雅的方法。
classinit()
将从创建的每个类中调用(不同于在父类上调用的3.6
\uuuu init\u子类)。至少我喜欢它,直到Python 3.5在
RuntimeError:super():empty\uuuuuu class\uuuuu.cell
中哭了出来

我读到它是因为我从元类的
\uuuuu init\uuuuu
方法中调用了一个方法,并且尽管类已经创建(因此我将代码放入
\uuuuuu init\uuuuu
,以初始化已经创建的东西),但它缺少这个
\uuu class\uuuuuu
单元,至少在那个时候

我试着在Python3.6中运行完全相同的代码,它成功了,所以我想有些地方出了问题,但得到了修复

我真正的问题是:

  • 在Python3.5中,我们真的可以用元类初始化类吗
  • 有没有办法避免在初始化过程中使用super()的限制
  • 为什么它在3.6中工作
  • 如果一切都失败了,那么仍然提供类初始化并允许超级(…)调用的最佳做法是什么?(比如我需要显式地引用超级类吗?)
提前谢谢你的帮助

编辑:

目标是能够派生组件,并能够以“简单”的方式相对于其父级初始化每个组件的类:


管理者是一个问题,我有多个概念,它们依赖于组件及其初始化类的能力;DR-如果您尝试从元类
\uuuuu new\uuuuu
\uuuu init\uuuu
方法中使用对
super
的空调用,那么您确实会遇到
运行时错误:super():empty\uuuuuu class\uuuuuuuuuuu单元格…
尚未创建由
super
内部使用的变量
\uuuuu class\uuuu
。(在验证这一点时,我刚刚发现Python3.6中已经解决了这一问题——也就是说,可以从Python3.6中元类的
\uuuu init\uuuu
调用使用无参数
super
的类方法,但在3.5中会产生此错误)

如果这是您目前唯一的方法,那么只需硬编码对超类方法的调用,就像在Python中创建
super
之前所需要的那样。(使用
super
的冗长形式也不起作用)

--

您的第二个也是最后一个想法,使用类方法作为注册的类装饰器,可以通过使用简单的Python名称mangling自动创建带有元类的
子管理器
属性,通过检查其
\uuu dict\uuuu
中一个类自己的名称空间来自动创建每个管理器类唯一的
子管理器
属性(也可以在没有元类的情况下完成)

使用元类,只需在元类的末尾添加这两行代码即可:

if getattr(cls, "SubManagers") and not "SubManagers" in cls.__dict__:
    cls.SubManagers = []
如果您的类装饰器方法以其他方式排除了元类,则不需要仅为此使用元类-更改register方法以执行上述“自己的”子管理器列表创建:

@classmethod
def RegisterSubManager(cls, manager):
   if not "SubManagers" in cls.__dict__:
       cls.SubManagers = []
   cls.SubManagers.append(manager)

如果您想让
管理器
类型具有额外的行为,那么您可能希望它们拥有自己的、更精细的元类,而不仅仅是使用从
组件
继承的元类。尝试编写从
元组件
继承的
元管理器
元类。您甚至可以将类方法从
Manager1
移动到元类中(在元类中它们成为普通方法):


好的,在一些实验之后,我设法提供了一个“修复”,以便允许类初始化,允许使用
super()

首先,模块要“修复”初始化方法:

。/PythonFix.py
进口检验
导入类型
def IsCellEmpty(单元):
“让我们继续深入下去!”
尝试:
cell.cell\u内容
返回错误
除值错误外:
返回真值
def ClosureFix(cls、functionContainer):
“这就是疯狂发生的地方。
我本来不想来这里的。但是,嘿,让我们生气吧。
必须这样做,以纠正在中发生的关闭问题
Python<3.6,joy。
非常感谢:https://stackoverflow.com/a/4885951/7983255
"""
#类是否以某种方式用@classmethod修饰
isclassmethod=inspect.ismethod(functionContainer)和functionContainer.\uuuuu self\uuuuuu是cls
如果是isclassmethod:
函数=函数容器__
其他:
函数=函数容器
#获取细胞并准备
@classmethod
def RegisterSubManager(cls, manager):
   if not "SubManagers" in cls.__dict__:
       cls.SubManagers = []
   cls.SubManagers.append(manager)
class MetaManager(MetaComponent):
    def __init__(cls, *args, **kwargs):
        super().__init__(*args, **kwargs)
        cls.SubManagers = [] # each class gets its own SubManagers list

    def ListSubManagers(cls):
        for manager in cls.SubManagers:
            print(manager)

    def RegisterSubManager(cls, manager):
        cls.SubManagers.append(manager)
        return manager

class Manager(Component, metaclass=MetaManager): # inherit from this to get the metaclass
    pass

class Manager1(Manager):
    pass

@Manager1.RegisterSubManager
class Manager2(Manager):
    pass

@Manager2.RegisterSubManager
class Manager3(Manager):
    pass
class MetaComponent(type):
    def __init__(cls:type, *args, **kargs) -> None:
        super().__init__(*args, **kargs)
        if hasattr(cls, 'classinit'):
            cls.classinit = PythonFix.ClosureFix(cls, cls.classinit)
            cls.classinit(**kargs)
        RegisterComponent(cls)

    def classinit(cls:type, **kargs) -> None:
        """The default classinit method."""
        pass

class Component(metaclass=MetaComponent):
    """This class self registers, inherit from this"""