Подтвердить что ты не робот

Определенные пользователем типы и коллекции .abc

У меня есть пакет Python, который определяет множество коллекций на основе ABC, предоставляемых collection.abc(Отображение, Последовательность и т.д.). Я хочу воспользоваться преимуществами типа hinting, введенными в Python 3.5, но у меня возникают сомнения относительно того, что будет лучшим способом для этого.

Давайте возьмем один из этих классов в качестве примера; до сих пор у меня было что-то похожее на это:

from collections.abc import Mapping

class MyMapping(Mapping):
    ...

Чтобы превратить это в общий тип, документация предлагает сделать что-то вроде этого:

from typing import TypeVar, Hashable, Mapping

K = TypeVar("K", bound=Hashable)
V = TypeVar("V")

class MyMapping(Mapping[K, V]):
    ...

Но это создает две проблемы:

  • Класс теряет все методы mixin из collection.abc.Mapping. Я мог бы справиться с этим, реализуя их сам, но это в первую очередь превзойдет часть использования ABC.

  • isinstance(MyMapping(), collections.abc.Mapping) возвращает значение False. Кроме того, при попытке вызвать collections.abc.Mapping.register(MyMapping) для работы над этим возникает RuntimeError ( "Отказ создать цикл наследования" ).

Моя первая попытка решить эти проблемы состояла в том, чтобы вернуться к расширению коллекций .abc.Mapping:

from typing import TypeVar, Hashable
from collections.abc import Mapping

K = TypeVar("K", bound=Hashable)
V = TypeVar("V")

class MyMapping(Mapping[K, V]):
    ...

Но это не работает, поскольку collection.abc.Mapping не является общим типом и не поддерживает оператор подписки. Поэтому я попробовал это:

from typing import TypeVar, Hashable, Mapping
from collections.abc import Mapping as MappingABC

K = TypeVar("K", bound=Hashable)
V = TypeVar("V")

class MyMapping(MappingABC, Mapping[K, V]):
    ...

Но это пахнет рыжим. Импорт и псевдонимы громоздки, в результате класс имеет извилистую MRO, а методы смешения, предоставляемые ABC, не будут печатать информацию...

Итак, какой предпочтительный способ объявить пользовательский общий тип на основе коллекции ABC?

4b9b3361

Ответ 1

[Personal Opinion ™]: Я действительно не поддерживаю создание новых typing функций. Они должны быть достаточно обобщенными, чтобы не требовать каких-либо изменений в вашем коде. Если ваш класс сопоставления настолько сложный, он не может быть заменен каким-либо общим отображением (например, dict), вам лучше просто использовать его:

def foo(bar: MyMapping) -> List:
    pass

вместо

def foo(bar: Mapping[K, V]) -> List:
    pass

Теперь, если вы хотите, чтобы ваши пользователи могли "набирать" свой класс с помощью typing.Mapping, вам просто нужно подклассом collections.Mapping

class MyMapping(collections.abc.Mapping):
    ... # define required methods

isinstance(MyMapping(), typing.Mapping[K, V]) # --> True

Ответ 2

Исходный код отлично работает с текущей версией python и mypy и выполняет все, что вам нужно (включая повторное использование реализации из collections.abc.Mapping).

Однако пока вы должны удалить bound=Hashable, так как еще не полностью поддерживается:

from typing import TypeVar, Hashable, Mapping

K = TypeVar("K")
V = TypeVar("V")

class MyMapping(Mapping[K, V]):
    ...