<p>您正试图在<code>class</code>语句完成</em>之前创建类的实例。类对象已创建,但尚未分配给全局名称。你知道吗</p>
<p>事件的顺序是:</p>
<ul>
<li>找到<code>class Dep_A</code>语句,执行类主体以形成属性(创建<code>__init__</code>函数)。你知道吗</li>
<li>调用元类<code>__new__</code>方法时使用类名、基和类主体名称空间(<code>'Dep_A'</code>、<code>(Department,)</code>和<code>{'__init__': <function ...>, ...}</code>)。你知道吗</li>
<li>元类创建新的类对象</li>
<li>元类调用<code>registry()</code>,传递新的类对象</li>
<li><code>registry()</code>调用类对象</li>
<li>调用类<code>__init__</code>方法</li>
</ul>
<p>通常,当元类<code>__new__</code>方法返回新创建的对象时,<code>Dep_A</code>被赋值。<em>在此之前,没有分配全局名称<code>Dep_A</code>,因此<code>super(Dep_A, self).__init__()</code>调用失败。你知道吗</p>
<p>您可以先从那里设置名称:</p>
<pre><code>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
</code></pre>
<p>或者,不要尝试在注册表中创建实例,而是存储一个类。以后可以创建一个实例。你知道吗</p>
<p>下面实现了一个注册表,该注册表在以后需要时透明地创建实例,并仅存储创建的一个实例:</p>
<pre><code>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
</code></pre>
<p>现在,类存储在单独的映射中,只有稍后从注册表映射中查找类时,才会创建并缓存实例:</p>
<pre><code>>>> 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'>}}
</code></pre>