Общий NamedTuple в Python 3.6 - PullRequest
0 голосов
/ 25 мая 2018

Я пытаюсь создать универсальную версию 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

Я не уверенкак еще добиться того, что я пытаюсь сделать здесь, или это может быть ошибка в механизме набора текста на каком-то уровне.

1 Ответ

0 голосов
/ 25 мая 2018

Так что это конфликт метаклассов, поскольку в 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=[''])

Насколько хорошо контролеры типов справляются с моим / вашим решением в python 3.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=[''])
...