我正在尝试使用元类自动注册子类,
但是以下代码在行
super(Dep_A,self).__init__().
*NameError: global name 'Dep_A' is not defined*
尝试了MetaClass中的注释行,但是出现了同样的错误。 我知道这在不使用元类时有效,所以如何初始化父类的init方法
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__()
...
答案 0 :(得分:2)
您正在尝试在class
语句完成之前创建类的实例。已创建类对象,但尚未将其分配给全局名称。
事件的顺序是:
class Dep_A
语句,并执行类主体以形成属性(创建__init__
函数)。__new__
,'Dep_A'
和(Department,)
)调用元类{'__init__': <function ...>, ...}
方法。registry()
,传入新的类对象registry()
调用类对象__init__
方法称为通常,当元类Dep_A
方法返回新创建的对象时,会分配__new__
。 在此之前没有分配全局名称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
或者,不要尝试在注册表中创建实例,而是存储一个类。您随后可以在上创建单个实例。
以下实现了一个注册表,该注册表在您需要的时候透明地创建实例,并且只存储创建的那个实例:
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
现在类存储在一个单独的映射中,只有当您稍后从注册表映射中查找该类时,才会创建并缓存实例:
>>> 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'>}}
答案 1 :(得分:1)
您的register
函数在实际定义全局名称之前尝试实例化Dep_A
。 (也就是说,在为Dep_A
分配调用元类的结果之前,仍在执行类语句的主体时调用它。)
您希望存储类本身:
def register(cls):
registry[cls.__name__] = cls # Not cls()
return cls