Мне кажется, проблема в том, что параметр cls
, передаваемый конструктору метакласса, на самом деле является ссылкой на метакласс, а не на создаваемый класс.Поскольку __new__
- это метод класса PluginMetaclass
, он ассоциируется с этим классом, как и любой обычный метод класса.Вы, вероятно, хотите зарегистрировать вновь созданный объект класса, который вы получаете от super(PluginMetaclass, cls).__new__(..)
.
Эта измененная версия работала для меня на 3.2:
class PluginMetaclass(type):
def __new__(cls, name, bases, attrs):
print("Called metaclass: %r" % cls)
print("Creating class with name: %r" % name)
newclass = super(PluginMetaclass, cls).__new__(cls, name, bases, attrs)
print("Registering class: %r" % newclass)
registry.append((name, newclass))
return newclass
и вызовы print()
показать, что происходит за кулисами:
>>> registry = []
>>>
>>> class Plugin(metaclass=PluginMetaclass):
... def __init__(self, stuff):
... self.stuff = stuff
...
Called metaclass: <class '__main__.PluginMetaclass'>
Creating class with name: 'Plugin'
Registering class: <class '__main__.Plugin'>
>>> class SpamPlugin(Plugin):
... def __init__(self, stuff):
... self.stuff = stuff
...
Called metaclass: <class '__main__.PluginMetaclass'>
Creating class with name: 'SpamPlugin'
Registering class: <class '__main__.SpamPlugin'>
>>> class BaconPlugin(Plugin):
... def __init__(self, stuff):
... self.stuff = stuff
...
Called metaclass: <class '__main__.PluginMetaclass'>
Creating class with name: 'BaconPlugin'
Registering class: <class '__main__.BaconPlugin'>
>>> c = SpamPlugin(0)
>>> b = BaconPlugin(0)
>>> mycls = registry[1][1]
>>> d = mycls(0)
>>> d
<__main__.SpamPlugin object at 0x010478D0>
>>> registry
[('Plugin', <class '__main__.Plugin'>),
('SpamPlugin', <class '__main__.SpamPlugin'>),
('BaconPlugin', <class '__main__.BaconPlugin'>)]
Редактировать: @ drone115b также решил эту проблему, используя __init__
вместо __new__
в PluginMetaclass
.Это, вероятно, лучший способ пойти в большинстве случаев.