问题
I'm trying to create a generic version of a NamedTuple, as follows:
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]
However, I get the following error:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
I'm not sure how else to achieve what I'm trying to do here, or if this might be a bug in the typing mechanism on some level.
回答1:
So this is a metaclass conflict since in python 3.6 the typing NamedTuple
and Generic
use different metaclasses (typing.NamedTupleMeta
and typing.GenericMeta
), which python can't handle. I'm afraid there is no solution to this, other than to subclass from tuple
and manually initialise the values:
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=[""])
Due to PEP 560 this is fixed in 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=[''])
How well type checkers handle my solution / yours in python 3.7 though I haven't checked. I suspect it may not be seamless.
Edit
I found another solution -- make a new metaclass
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=[''])
来源:https://stackoverflow.com/questions/50530959/generic-namedtuple-in-python-3-6