在继承 metaclass 的 class 中调用 super 会抛出错误
Calling super in a class inheriting a metaclass throws an error
我正在尝试使用元class、
自动注册子classes
但是下面的代码在 class Dep_A 行
中抛出错误
super(Dep_A,self).__init__().
*NameError: global name 'Dep_A' is not defined*
尝试了 MetaClass 中的注释行,但出现相同的错误。
我知道这在不使用 metaclass 时有效,所以我如何初始化父 class 的初始化方法
registry = {}
def register(cls):
print cls.__name__
registry[cls.__name__] = cls()
return cls
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
register(newclass)
return newclass
class Department(object):
__metaclass__ = MetaClass
def __init__(self):
self.tasks = dict()
class Dep_A(Department):
def __init__(self):
super(Dep_A,self).__init__()
...
您的 register
函数试图在实际定义全局名称之前实例化 Dep_A
。 (也就是说,它在 class 语句的主体仍在执行时被调用,在 Dep_A
被分配给元 class 的调用结果之前。)
您想存储class本身:
def register(cls):
registry[cls.__name__] = cls # Not cls()
return cls
您正在尝试在 class
语句完成 之前创建 class 的实例。 class 对象已创建,但尚未分配给全局名称。
事件顺序是:
- 找到
class Dep_A
语句,执行class体形成属性(创建__init__
函数)
- metaclass
__new__
方法使用 classname、bases 和 class body 命名空间('Dep_A'
、(Department,)
和 {'__init__': <function ...>, ...}
)。
- 元class 创建新的class 对象
- 元class调用
registry()
,传入新的class对象
registry()
调用 class 对象
- 调用了class
__init__
方法
通常,Dep_A
是在metaclass __new__
方法returns 新创建的对象时赋值的。 在那之前 没有分配全局名称 Dep_A
,因此 super(Dep_A, self).__init__()
调用失败。
您可以先从那里设置名称:
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
globals()[clsname] = newclass
register(newclass)
return newclass
或者,不要尝试在注册表中创建实例,而是存储 class。您始终可以在 以后 .
创建单个实例
下面实现了一个注册表,当你需要一个实例时,它会透明地创建一个实例,并只存储创建的一个实例:
from collections import Mapping
class Registry(Mapping):
def __init__(self):
self._classes = {}
self._instances = {}
def __getitem__(self, name):
if name not in self._instances:
self._instances[name] = self._classes.pop(name)()
return self._instances[name]
def __iter__(self):
return iter(self._classes.viewkeys() | self._instances.viewkeys())
def __len__(self):
return len(self._classes) + len(self._instances)
def register(self, cls):
self._classes[cls.__name__] = cls
registry = Registry()
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
registry.register(newclass)
return newclass
现在 classes 存储在单独的映射中,只有当您稍后从注册表映射中查找 class 时,才会创建和缓存实例:
>>> class Department(object):
... __metaclass__ = MetaClass
... def __init__(self):
... self.tasks = dict()
...
>>> class Dep_A(Department):
... def __init__(self):
... super(Dep_A,self).__init__()
...
>>> registry.keys()
['Department', 'Dep_A']
>>> registry['Dep_A']
<__main__.Dep_A object at 0x110536ad0>
>>> vars(registry)
{'_instances': {'Dep_A': <__main__.Dep_A object at 0x110536ad0>}, '_classes': {'Department': <class '__main__.Department'>}}
我正在尝试使用元class、
自动注册子classes
但是下面的代码在 class Dep_A 行
super(Dep_A,self).__init__().
*NameError: global name 'Dep_A' is not defined*
尝试了 MetaClass 中的注释行,但出现相同的错误。 我知道这在不使用 metaclass 时有效,所以我如何初始化父 class 的初始化方法
registry = {}
def register(cls):
print cls.__name__
registry[cls.__name__] = cls()
return cls
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
register(newclass)
return newclass
class Department(object):
__metaclass__ = MetaClass
def __init__(self):
self.tasks = dict()
class Dep_A(Department):
def __init__(self):
super(Dep_A,self).__init__()
...
您的 register
函数试图在实际定义全局名称之前实例化 Dep_A
。 (也就是说,它在 class 语句的主体仍在执行时被调用,在 Dep_A
被分配给元 class 的调用结果之前。)
您想存储class本身:
def register(cls):
registry[cls.__name__] = cls # Not cls()
return cls
您正在尝试在 class
语句完成 之前创建 class 的实例。 class 对象已创建,但尚未分配给全局名称。
事件顺序是:
- 找到
class Dep_A
语句,执行class体形成属性(创建__init__
函数) - metaclass
__new__
方法使用 classname、bases 和 class body 命名空间('Dep_A'
、(Department,)
和{'__init__': <function ...>, ...}
)。 - 元class 创建新的class 对象
- 元class调用
registry()
,传入新的class对象 registry()
调用 class 对象- 调用了class
__init__
方法
通常,Dep_A
是在metaclass __new__
方法returns 新创建的对象时赋值的。 在那之前 没有分配全局名称 Dep_A
,因此 super(Dep_A, self).__init__()
调用失败。
您可以先从那里设置名称:
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
globals()[clsname] = newclass
register(newclass)
return newclass
或者,不要尝试在注册表中创建实例,而是存储 class。您始终可以在 以后 .
创建单个实例下面实现了一个注册表,当你需要一个实例时,它会透明地创建一个实例,并只存储创建的一个实例:
from collections import Mapping
class Registry(Mapping):
def __init__(self):
self._classes = {}
self._instances = {}
def __getitem__(self, name):
if name not in self._instances:
self._instances[name] = self._classes.pop(name)()
return self._instances[name]
def __iter__(self):
return iter(self._classes.viewkeys() | self._instances.viewkeys())
def __len__(self):
return len(self._classes) + len(self._instances)
def register(self, cls):
self._classes[cls.__name__] = cls
registry = Registry()
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
registry.register(newclass)
return newclass
现在 classes 存储在单独的映射中,只有当您稍后从注册表映射中查找 class 时,才会创建和缓存实例:
>>> class Department(object):
... __metaclass__ = MetaClass
... def __init__(self):
... self.tasks = dict()
...
>>> class Dep_A(Department):
... def __init__(self):
... super(Dep_A,self).__init__()
...
>>> registry.keys()
['Department', 'Dep_A']
>>> registry['Dep_A']
<__main__.Dep_A object at 0x110536ad0>
>>> vars(registry)
{'_instances': {'Dep_A': <__main__.Dep_A object at 0x110536ad0>}, '_classes': {'Department': <class '__main__.Department'>}}