且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Python 3.6中的通用NamedTuple

更新时间:2021-11-14 04:18:26

所以这是一个元类冲突,因为在python 3.6中,键入NamedTupleGeneric使用不同的元类(typing.NamedTupleMetatyping.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=[''])