python 3.2插件工厂:从类/元类实例化

python 3.2插件工厂:从类/元类实例化,python,factory-pattern,metaclass,Python,Factory Pattern,Metaclass,我从这里的信息中重复: 我的问题是,我无法使用该类注册表创建对象的实例。如果我使用“常规”构造方法,那么它似乎可以正确地实例化对象;但是,当我尝试使用与注册表关联的类对象时,会出现一个错误,即我传递的参数数量不正确。(似乎在调用元类new,而不是我的构造函数…?) 我不清楚为什么会失败,因为我认为我应该能够使用“可调用”语法从类对象创建实例 看来我把元类放在注册表中,而不是类本身?但是在new调用中,我看不到访问类本身的简单方法 下面是我的代码示例,无法实例化变量“d”: registry =

我从这里的信息中重复:

我的问题是,我无法使用该类注册表创建对象的实例。如果我使用“常规”构造方法,那么它似乎可以正确地实例化对象;但是,当我尝试使用与注册表关联的类对象时,会出现一个错误,即我传递的参数数量不正确。(似乎在调用元类new,而不是我的构造函数…?)

我不清楚为什么会失败,因为我认为我应该能够使用“可调用”语法从类对象创建实例

看来我把元类放在注册表中,而不是类本身?但是在new调用中,我看不到访问类本身的简单方法

下面是我的代码示例,无法实例化变量“d”:

registry = [] # list of subclasses class PluginMetaclass(type): def __new__(cls, name, bases, attrs): print(cls) print(name) registry.append((name, cls)) return super(PluginMetaclass, cls).__new__(cls, name, bases, attrs) class Plugin(metaclass=PluginMetaclass): def __init__(self, stuff): self.stuff = stuff # in your plugin modules class SpamPlugin(Plugin): def __init__(self, stuff): self.stuff = stuff class BaconPlugin(Plugin): def __init__(self, stuff): self.stuff = stuff c = SpamPlugin(0) b = BaconPlugin(0) mycls = registry[1][1] d = mycls(0) 注册表=[]#子类列表 类PluginMetaclass(类型): 定义(cls、名称、基数、属性): 打印(cls) 印刷品(名称) registry.append((名称,cls)) 返回super(PluginMetaclass,cls)。\uuuu新的(cls,name,base,attrs) 类插件(元类=插件元类): 定义初始化(self,stuff): self.stuff=stuff #在插件模块中 SpamPlugin类(插件): 定义初始化(self,stuff): self.stuff=stuff BaconPlugin类(插件): 定义初始化(self,stuff): self.stuff=stuff c=SpamPlugin(0) b=BaconPlugin(0) mycls=注册表[1][1] d=mycls(0)
谢谢您的帮助。

我认为您遇到的问题是传递给元类构造函数的
cls
参数实际上是对元类的引用,而不是正在创建的类。由于
\uuuu new\uuuu
PluginMetaclass
的一个类方法,它与该类的关联就像任何常规类方法一样。您可能想注册从
super(PluginMetaclass,cls)获得的新创建的类对象

此修改版本在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'>)]
>>注册表=[]
>>>
>>>类插件(元类=插件元类):
...     定义初始化(self,stuff):
...         self.stuff=stuff
...
称为元类:
正在创建名为“Plugin”的类
注册类别:
>>>SpamPlugin类(插件):
...     定义初始化(self,stuff):
...         self.stuff=stuff
...
称为元类:
正在创建名为“SpamPlugin”的类
注册类别:
>>>BaconPlugin类(插件):
...     定义初始化(self,stuff):
...         self.stuff=stuff
...
称为元类:
正在创建名为“BaconPlugin”的类
注册类别:
>>>c=SpamPlugin(0)
>>>b=BaconPlugin(0)
>>>mycls=注册表[1][1]
>>>d=mycls(0)
>>>d
>>>登记处
[('Plugin',),
(‘SpamPlugin’,),
('BaconPlugin',)]

Edit:@drone115b也通过使用
\uuuuu init\uuuuuuu
而不是
PluginMetaclass
中的
\uuuuu new\uuuuuuuuuuuuuuuu>解决了这个问题。在大多数情况下,这可能是更好的方法。

是的,格雷格,谢谢。我昨天猜测并测试了几个小时,然后找到了一个更简单的解决方案。用init替换new,第一个参数是类名而不是元类名。调用super.\uuuinit\uuuuuuu需要删除第一个参数,否则它是对原始代码的修复,只涉及将新代码更改为init。我当然希望文档在元类的可用界面上更清晰。我还应该说,我个人有一点倾向于使用init而不是new。Init是一个验证,而new是一个分配。我不想在较低的细节层次上胡闹,我认为类注册更像是一个验证步骤。不过,无论哪种方法都确实有效。我同意,
\uuuuu init\uuuu
对我来说也感觉更好,而且肯定更适合这个应用程序。我认为对
\uuuuu new\uuuuuu
的需求通常是相当少的,尤其是对于元类来说。