Создать новый подтип int mypy, совместимый с int - PullRequest
0 голосов
/ 12 июля 2020

Я хочу расширить тип int таким образом, чтобы mypy по-прежнему распознавал его как int. Например:

class u8(int):
    _size_bits = 8
    _struct_format: str = 'B'

    def validate(self):
        "Internal function. Mypy shouldn't care about it"
        return 0 <= int(self) <= 255

, поэтому я могу использовать

i: u8 = 10

, но mypy дает ошибку

Incompatible types in assignment (expression has type "int", variable has type "u8")

Предположим, он использует PEP 563, ie. from __future__ import annotations.

Приведение его в таком виде будет работать, но это приведет к загрязнению, создаст ненужные накладные расходы, и это должно работать в существующем коде только изменение подсказки типа, а не кода :

i: u8 = u8(10)

Таким образом, единственное необходимое изменение - это добавление подсказки типа, а не изменение остальной части кода. И он должен нормально работать и без набора текста. если я удалю библиотеку (при условии, что PEP 563), код должен работать нормально, даже если в этом случае он выдаст ошибку на Mypy:

from __future__ import annotations

i: u8 = 10  # Works OK without the u8 definition

i: u8 = u8(10)  # ERROR: u8 is not defined here.

Я также пробовал использовать abc.ABC с регистром, но он не работает :

class u8(int, ABC):
    ...

u8.register(int)

Это кажется простой задачей, и мне, должно быть, здесь не хватает чего-то довольно очевидного, но все поиски в Google до сих пор не помогли.

Ответы [ 2 ]

1 голос
/ 12 июля 2020

Вы пытаетесь втиснуть в аннотации информацию, не относящуюся к типу, в пользу инструмента, который вы создаете. Вы пытались сделать это, создав подтип, но это не означает то, что вы хотите, и mypy правильно выдает ошибку.

Функция для того, что вы хотите, входит в Python 3.9, с backport, доступным для большинства предыдущих версий (3.5.3+ и, возможно, 2.7) в typing_extensions. Это аннотация Annotated, предложенная в PEP 593 . С помощью Annotated вы можете определить

u8 = Annotated[int, whatever_arbitrary_data]

и аннотировать такие вещи, как

i: u8 = 10

, и mypy распознает, что int - это тип, а whatever_arbitrary_data - это чья-то проблема.

0 голосов
/ 12 июля 2020

Обходной путь, который я нашел до сих пор, - определить класс как int, когда TYPE_CHECKING истинно. Приведенный выше пример, кажется, радует mypy и дает то, что мне нужно во время выполнения:

from typing import TYPE_CHECKING

class _u8(int):
    _size_bits = 8
    _struct_format: str = 'B'

    def validate(self):
        return 0 <= int(self) <= 255

if TYPE_CHECKING:
    u8 = int
else:
    u8 = _u8

i: u8 = 10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...