我正在尝试创建namedtuple的通用版本,如下所示:
T1 = TypeVar("T1")
T2 = TypeVar("T2")
class Group(NamedTuple, Generic[T1, T2]):
key: T1
group: List[T2]
g = Group(1, [""]) # expecting type to be Group[int, str]
但是,我得到以下错误:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
我不知道还有什么方法可以实现我在这里要做的,或者这在某种程度上可能是输入机制中的一个bug。
最佳答案
因此这是一个元类冲突,因为在python 3.6中,输入NamedTuple
和Generic
使用不同的元类(typing.NamedTupleMeta
和typing.GenericMeta
),python无法处理这些元类。恐怕除了从tuple
中进行子类划分并手动初始化这些值之外,没有其他解决方案:
T1 = TypeVar("T1")
T2 = TypeVar("T2")
class Group(tuple, Generic[T1, T2]):
key: T1
group: List[T2]
def __new__(cls, key: T1, group: List[T2]):
self = tuple.__new__(cls, (key, group))
self.key = key
self.group = group
return self
def __repr__(self) -> str:
return f'Group(key={self.key}, group={self.group})'
Group(1, [""]) # --> Group(key=1, group=[""])
由于PEP 560这在python 3.7中是固定的:
Python 3.7.0b2 (v3.7.0b2:b0ef5c979b, Feb 28 2018, 02:24:20) [MSC v.1912 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing import *
>>> T1 = TypeVar("T1")
>>> T2 = TypeVar("T2")
>>> class Group(NamedTuple, Generic[T1, T2]):
... key: T1
... group: List[T2]
...
>>> g = Group(1, [""])
>>> g
Group(key=1, group=[''])
类型检查程序在Python3.7中处理我的解决方案/你的解决方案有多好,尽管我还没有检查。我怀疑这可能不是天衣无缝的。
编辑
我找到了另一个解决方案--创建一个新的元类
import typing
from typing import *
class NamedTupleGenericMeta(typing.NamedTupleMeta, typing.GenericMeta):
pass
class Group(NamedTuple, Generic[T1,T2], metaclass=NamedTupleGenericMeta):
key: T1
group: List[T2]
Group(1, ['']) # --> Group(key=1, group=[''])