Как определить TypeVar для Counter[str] с подсказкой типа Python 3.5

Вопрос 1:

Я хотел бы определить псевдоним типа мешка слов, используя синтаксис подсказки типа Python 3.5, что-то вроде строк:

from collections import Counter
from typing import TypeVar

# define bag-of-words type
Bow = TypeVar('Bow', Counter[str])

def process_bag_of_words(bag_of_words: Bow) -> Bow:
    ...

Проблема в том, что я не знаю, как заставить Counter принимать аргумент типа для своих ключей (в данном случае str; его значения всегда ints).

Опция 1:

Поскольку counter является подклассом dict, альтернативой может быть что-то вроде:

from typing import TypeVar, Dict

# define bag-of-words type
Bow = TypeVar('Bow', Dict[str, int])

Хотя это не гарантирует, что я работаю с Counter, а не с Dict.

Вариант 2:

Другой вариант — определить Bow как простой тип Counter, например:

from collections import Counter
from typing import TypeVar

# define bag-of-words type
Bow = TypeVar('Bow', Counter)

Однако это тоже не очень хорошо, поскольку не применяет тип ключа к счетчику.

Есть ли правильный способ справиться с этой ситуацией? Если так, то, что это?

Вопрос 2:

Если бы я создавал свой собственный класс, как бы я мог принять параметр универсального типа? Итак, если бы я объявил класс Foo в модуле с именем my_module, как бы я сделал это законным:

from typing import TypeVar
from my_module import Foo

FooTypeAlias = TypeVar('FooTypeAlias', Foo[str])

person kevin    schedule 02.01.2016    source источник


Ответы (1)


Цель TypeVar – служить заполнителем в объявлении универсального класса или автономной универсальной функции.

То, что вы ищете в вопросе 1, может быть примерно следующим:

import typing as tg
from collections import Counter

class Bow(Counter, tg.Mapping[str, int]):
    pass

И чтобы сделать общий "мешок с произвольным материалом" (удавы), вы должны использовать:

import typing as tg
from collections import Counter

S = tg.TypeVar('S')  # STUFF

class Boas(Counter, tg.Mapping[S, int]):
    pass

В обоих случаях тело класса не требуется: вся функциональность будет унаследована от Counter, а все типы будут получены от tg.Mapping в следующем смысле: если вы объявите, например,

def foo(bag: Bow, what):
    n = bag[what]
    #...

проверка статического типа (если есть файл-заглушка для Counter или аннотации типов в реализации Counter) должна сделать вывод, что n будет int, и может сделать вывод или предположить что what будет str. Проверка динамического типа (активируется путем декорирования foo, пакет PyPI typecheck-decorator скоро предоставит что-то подходящее) может просматривать фактический объект bag при вызове foo и проверять, что некоторые или все ключи являются str и соответствующие значения должны быть int.

person Lutz Prechelt    schedule 22.01.2016
comment
Это именно та проблема, с которой я сейчас сталкиваюсь, за исключением того, что я специально НЕ хочу создавать псевдоним/имя типа для типа Counter[str]. Это тоже возможно? - person paul23; 29.01.2017