What's the correct way to implement a metaclass with a different signature than `type`?
假设我想实现一个应该作为类工厂使用的元类。但是,与使用3个参数的
1 2 3 | Cls1 = MyMeta() Cls2 = MyMeta() ... |
为此,我定义了一个没有参数的自定义
1 2 3 | class MyMeta(type): def __new__(cls): return super().__new__(cls, 'MyCls', (), {}) |
但问题是,python自动调用
1 | TypeError: type.__init__() takes 1 or 3 arguments |
这是有意义的,因为可以用1或3个参数调用
- 我可以在我的元类中添加一个空的
__init__ 方法,但是由于我不确定type.__init__ 是否做了重要的事情,这可能不是一个好主意。 - 我可以实现一个调用
super().__init__(cls.__name__, cls.__bases__, vars(cls)) 的__init__ 方法。 - 我可以使用一个元类并重写它的
__call__ 方法,而不是与__new__ 和__init__ 混淆。 - 奖金选项:也许我不应该尝试更改签名?
所以我的问题是:我列出的3个解决方案是否正确,或者其中是否隐藏了一些细微的缺陷?哪种解决方案是最好的(即最正确的)?
在常规类中,偏离父签名的接口也是一种有问题的设计。你不需要超复杂的元类就可以进入这种混乱状态——你可以通过子类化一个
I want to have a metaclass and an easy way to create instances of that metaclass.
在python中,通常的模式是使用
这里没有特定于元类的内容,因此请使用相同的模式:
1 2 3 4 5 6 | class MyMeta(type): @classmethod def from_no_args(cls, name=None): if name is None: name = cls.__name__ + 'Instance' return cls(name, (), {}) |
用途:
1 2 3 4 5 6 7 8 9 10 11 | >>> class A(metaclass=MyMeta): ... pass ... >>> B = MyMeta.from_no_args() >>> C = MyMeta.from_no_args(name='C') >>> A.__name__ 'A' >>> B.__name__ 'MyMetaInstance' >>> C.__name__ 'C' |