更新时间:2021-11-14 04:18:26
所以这是一个元类冲突,因为在python 3.6中,键入NamedTuple
和Generic
使用不同的元类(typing.NamedTupleMeta
和typing.GenericMeta
), python无法处理.恐怕除了从tuple
继承并手动初始化值之外,没有其他解决方案:
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=[""])
由于PEP 560 和 563 在python 3.7中已解决:
Due to PEPs 560 and 563 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 __future__ import annotations
>>> from typing import *
>>> T1 = TypeVar("T1")
>>> T2 = TypeVar("T2")
>>> class Group(NamedTuple, Generic[T1, T2]):
... key: T1
... group: List[T2]
...
>>> g: Group[int, str] = Group(1, [""])
>>> g
Group(key=1, group=[''])
当然,在python 3.7中,您只能使用轻量级(可变)但具有类似用途的数据类.
Of course in python 3.7 you can just use a dataclass which are less lightweight (and mutable) but serve similar purposes.
from dataclasses import dataclass, astuple
from typing import Generic, TypeVar, List
T1 = TypeVar('T1')
T2 = TypeVar('T2')
@dataclass
class Group(Generic[T1, T2]):
key: T1
group: List[T2]
# if you want to be able to unpack like a tuple...
def __iter__(self):
yield from astuple(self)
g: Group[int, str] = Group(1, ['hello', 'world'])
k, v = g
print(g)
尽管我尚未检查类型检查器在python 3.7中如何处理我的解决方案/您的解决方案.我怀疑这可能不是无缝的.
How well type checkers handle my solution / yours in python 3.7 though I haven't checked. I suspect it may not be seamless.
我找到了另一个解决方案-制作一个新的元类
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=[''])