【发布时间】:2018-02-02 22:03:06
【问题描述】:
我最近偶然发现了 Python 中的元类,并决定使用它们来简化一些功能。 (使用 Python 3.5)
简而言之,我正在编写一个定义类的模块,例如必须注册和初始化的“组件”(我的意思是我需要初始化实际的类,而不是实例)。
我可以轻松注册课程:
class MetaComponent(type):
def __init__(cls, *args, **kargs):
super().__init__(*args, **kargs)
RegisterComponent(cls)
class BaseComponent(metaclass=MetaComponent):
pass
class Component(BaseComponent):
"""This is the actual class to use when writing components"""
在这种情况下,我正在注册组件的类,因为它允许我稍后引用它们,而无需它们的实际引用。
但是类缺乏自我初始化的能力(至少在 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 字段在每个子类之间共享......所以添加到一个列表会添加到每个子类。 RIP。
所以下一个想法是实现一种初始化器:
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)
我认为自己已经完成了这个。有点优雅的方式来做IMO。 classinit() 将从正在创建的每个类中调用(与在父级上调用的 3.6 __init_subclass__ 不同)。至少我喜欢它,直到 Python 3.5 在 RuntimeError: super(): empty __class__ cell 中哭泣...
我读到它是因为我从元类的 __init__ 方法中调用了一个方法,并且虽然创建了这个类(因此我愿意将代码放在 __init__ 中,以初始化已经创建的东西),但它缺少这个 @ 987654331@细胞,至少在那一刻……
我尝试在 Python 3.6 中运行完全相同的代码,它运行正常,所以我猜是有问题但得到了修复......
我真正的问题是:
- 我们真的可以在 Python 3.5 中用元类初始化类吗?
- 有没有办法在初始化过程中避免 super() 的使用限制?
- 为什么它在 3.6 中工作?
- 如果一切都失败了,那么仍然提供类初始化并允许调用 super(...) 的最佳做法是什么? (我是否需要明确地引用超类?)
提前感谢您的帮助。
编辑:
目标是能够以“简单”的方式派生组件并能够相对于其父级初始化每个类:
class Manager(Component):
def classinit(cls, **kargs):
cls.SubManagers = []
@classmethod
def RegisterSubManager(cls, manager):
cls.SubManagers.append(manager)
return manager
@Manager.RegisterSubManager
class EventManager(Manager):
def classinit(cls, **kargs):
super().classinit(**kargs) # keep the old behaviour
cls.Events = []
# ...
@EventManager.RegisterSubManager
class InputManager(EventManager):
def classinit(cls, **kargs):
super().classinit(**kargs) # again, keep old behaviour
cls.Inputs = []
# use parts of EventManager, but define specialized methods
# for input management
管理器是一个问题,我有多个依赖于组件及其初始化类的能力的概念。
【问题讨论】:
-
我不明白
@Manager2.RegisterSubManager是如何工作的,因为Manager2不是Manager1的子类。 -
我的错误,已修复
标签: python metaprogramming python-3.5 metaclass