假设我想实现一个应该作为类工厂的元类.但与type构造函数不同,构造函数需要3个参数,我的元类应该可以调用而不带任何参数:
Cls1 = MyMeta()
Cls2 = MyMeta()
...
Run Code Online (Sandbox Code Playgroud)
为此,我定义了一个__new__没有参数的自定义方法:
class MyMeta(type):
def __new__(cls):
return super().__new__(cls, 'MyCls', (), {})
Run Code Online (Sandbox Code Playgroud)
但问题是python自动使用与__init__方法相同的参数__new__调用方法,因此尝试调用MyMeta()最终会抛出异常:
TypeError: type.__init__() takes 1 or 3 arguments
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为type可以用1或3个参数调用.但是解决这个问题的正确方法是什么?我看到3(4?)选项:
__init__在我的元类中添加一个空方法,但由于我不确定是否type.__init__有任何重要的事情,这可能不是一个好主意.__init__调用的方法super().__init__(cls.__name__, cls.__bases__, vars(cls)).__call__方法,而不是搞乱__new__和__init__.所以我的问题是:我列出的3个解决方案是正确的还是隐藏在其中的任何微妙的错误?哪种解决方案最好(即最正确)?
偏离父签名的界面也是常规类中的可疑设计.你不需要额外的复杂的元类来进入这种混乱 - 你可以通过继承a datetime或其他东西导致相同的new/init混乱.
我希望有一个元类和一种简单的方法来创建该元类的实例.
Python中通常的模式是使用from_somethingclassmethod 编写工厂.要采取从不同的init签名产生的datetime实例的例子,例如存在datetime.fromtimestamp,但你有很多其他的例子太(dict.fromkeys,int.from_bytes,bytes.fromhex...)
这里没有特定于元类的东西,所以使用相同的模式:
class MyMeta(type):
@classmethod
def from_no_args(cls, name=None):
if name is None:
name = cls.__name__ + 'Instance'
return cls(name, (), {})
Run Code Online (Sandbox Code Playgroud)
用法:
>>> 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'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
166 次 |
| 最近记录: |