Python3.5:使用继承进行类初始化
我最近在Python中偶然发现了元类,并决定使用它们来简化一些特性。(使用Python 3.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): “”“这是编写组件时要使用的实际类”“” 在本例中,我正在注册组件
类元组件(类型):
定义初始值(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"""