Вы пытаетесь создать экземпляр класса до того, как оператор class
завершил .Объект класса создан, но еще не присвоен глобальному имени.
Порядок событий:
- найден оператор
class Dep_A
и класстело выполняется для формирования атрибутов (создается функция __init__
). - метод метакласса
__new__
вызывается с именем класса, основами и пространством имен тела класса ('Dep_A'
, (Department,)
и{'__init__': <function ...>, ...}
соответственно). - метакласс создает новый объект класса
- Метакласс вызывает
registry()
, передавая новый объект класса registry()
вызывает классobject - Метод класса
__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'>}}