Как обрабатывать неподдерживаемые типы операндов в mypy, когда тип должен быть четким?

Рассмотрим следующий пример с игрушкой.

class MyClass:
    def __init__(self, optional_arg: float | None = None) -> None:
        self.optional_arg = optional_arg

        self._parse_args()

    def _parse_args(self) -> None:
        if self.optional_arg is None:
            self.optional_arg = 0.5

    def multiply(self) -> float:
        # mypy is complaining with the below statement:
        # error: Unsupported operand types for * ("float" and "None")  [operator]
        # Right operand is of type "Optional[float]"
        return 0.5 * self.optional_arg

После создания экземпляра этого класса с помощью optional_arg=None должно быть ясно, что self.optional_arg будет установлен в float из-за метода _parse_args.

На мой взгляд, должно быть ясно, что при вызове метода multiply он вернет float. Однако mypy все еще жалуется, что self.optional_arg может быть None.

Что такое питонический способ сказать mypy, что self.optional_arg не может быть None?

Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
Учебник по веб-скрапингу
Учебник по веб-скрапингу
Привет, ребята... В этот раз мы поговорим о веб-скрейпинге. Целью этого обсуждения будет узнать и понять, что такое веб-скрейпинг, а также узнать, как...
Тонкая настройка GPT-3 с помощью Anaconda
Тонкая настройка GPT-3 с помощью Anaconda
Зарегистрируйте аккаунт Open ai, а затем получите ключ API ниже.
Learning Data Analytics Two: Filtering data in a DataFrame.
Learning Data Analytics Two: Filtering data in a DataFrame.
В Learning Data Analytics One: Using Python and Pandas , я рассказываю о:
1
0
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Self.optional_arg не обязательно должно быть значением, установленным _parse_args. Кто-то может сделать

x = MyClass()
x.optional_arg = None
x.multiply()

И что касается mypy, это допустимый способ использования MyClass.

Кроме того, кто-то может переопределить _parse_args:

class Subclass(MyClass):
    def _parse_args(self) -> None:
        pass

Subclass().multiply()

И что касается mypy, это тоже законно.

Если вы хотите, чтобы mypy обрабатывал self.optional_arg как никогда None, вы не должны устанавливать для него значение, которое может быть None в первую очередь. Вы можете использовать float по умолчанию в первую очередь:

class MyClass:
    optional_arg: float
    def __init__(self, optional_arg: float = 0.5) -> None:
        self.optional_arg = optional_arg
    ...

Или сделайте свою None обработку, прежде чем установить атрибут:

class MyClass:
    optional_arg: float
    def __init__(self, optional_arg: float | None = None) -> None:
        self.optional_arg = optional_arg if optional_arg is not None else 0.5
    ...

Или сделайте def __init__(self, optional_arg: float = 0.5) -> None: и вообще исключите _parse_args.

Jasmijn 13.02.2023 09:45

Ответ пользователя 2357112 отличный, и в этом случае вы должны пойти на это. Однако не всегда легко иметь правильную типизацию (особенно при работе с устаревшим кодом). В таком случае можно использовать сужение типа .

     def multiply(self) -> float:
        assert isinstance(self.optional_arg, float)
        return 0.5 * self.optional_arg

Тоже очень полезный совет! Потрясающий.

Andi 13.02.2023 10:28

Другие вопросы по теме