如何在调用type函数时指定metaclass,解决Python元类冲突问题?
Python元类冲突:使用
type()函数正确指定合并元类的方法 问题场景
定义继承自B和C的类A时,触发元类冲突错误:
>>> class A(B, C): ... pass ... TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
在类定义语句中,通过自定义merged函数生成合并元类可解决该问题:
def merged(*parents): return type("meta", tuple(type(p) for p in parents), {}) class A(B, C, metaclass=merged(B, C)): pass
但使用type()三参数形式创建类时,传入metaclass关键字参数仍触发相同错误:
def merged(*parents): return type("meta", tuple(type(p) for p in parents), {}) # 错误写法 A = type("A", (B, C), {}, metaclass=merged(B, C))
错误原因
根据Python官方文档说明:
三参数形式的type函数接收的关键字参数,会以类定义中除metaclass外的关键字参数相同的方式,传递给对应的元类机制(通常是__init_subclass__())。
也就是说,type()的关键字参数并非用来指定元类,它的默认元类是type本身;而类定义中的metaclass参数是直接指定创建类的元类,二者逻辑不同。
正确解法
要通过type()实现和类定义语句等价的效果,需直接使用合并后的元类来创建新类,有两种简洁写法:
写法一:先获取合并元类再创建类
def merged(*parents): return type("meta", tuple(type(p) for p in parents), {}) # 生成合并后的元类 Meta = merged(B, C) # 用该元类创建类A A = Meta("A", (B, C), {})
写法二:链式调用合并元类
def merged(*parents): return type("meta", tuple(type(p) for p in parents), {}) # 直接调用合并后的元类创建类A,等价于class定义语句 A = merged(B, C)("A", (B, C), {})
原理说明
Python类定义语句class A(B, C, metaclass=Meta): ...的底层逻辑是:指定Meta作为元类,调用Meta的__new__和__init__方法生成类对象。而type(name, bases, dict, **kwds)的逻辑是默认用type作为元类,将关键字参数传递给元类的子类初始化机制,而非指定元类本身。因此必须直接调用目标元类来创建新类。
内容的提问来源于stack exchange,提问作者Robin De Schepper
相关产品推荐
相关产品推荐

