Тип подсказывает, что функция никогда не возвращается - программирование

Тип подсказывает, что функция никогда не возвращается

Новая функция тип подсказки в Python позволяет нам вводить подсказку о том, что функция возвращает None...

def some_func() -> None:
    pass

... или оставить неопределенный тип возвращаемого значения, который диктует PEP, должен заставить статические анализаторы предположить, что возможен любой тип возврата:

Любая функция без аннотаций должна рассматриваться как имеющая наиболее общий тип

Однако, как мне ввести подсказку о том, что функция никогда не вернется? Например, как правильно ввести тип, возвращающий значение этих двух функций?

def loop_forever():
    while True:
        print('This function never returns because it loops forever')

def always_explode():
    raise Exception('This function never returns because it always raises')

Ничто не указывает -> None и не оставляет тип возвращаемого значения неуказанным в этих случаях.

4b9b3361

Ответ 1

Несмотря на то, что " PEP 484 - Type Hints" стандарт упоминается как в вопросе, так и в ответе, но никто не цитирует его раздел: Тип NoReturn, который охватывает ваш вопрос.

Цитата:

Модуль typing предоставляет специальный тип NoReturn для комментирования функций, которые никогда не возвращаются нормально. Например, функция, которая безоговорочно вызывает исключение:

from typing import NoReturn

def stop() -> NoReturn:
    raise RuntimeError('no way')

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

Ответ 2

В июле 2016 года еще не было ответа на этот вопрос (теперь есть NoReturn, см. новый принятый ответ). Это были некоторые из причин:

  • Когда функция не возвращается, нет возвращаемого значения (даже не None), которому может быть присвоен тип. Таким образом, вы на самом деле не пытаетесь аннотировать тип; вы пытаетесь аннотировать отсутствие типа.

  • Тип hinting PEP только что был принят в стандарте, начиная с версии 3.5 Python. Кроме того, PEP только советует, какой тип аннотаций должен выглядеть, будучи преднамеренно неопределенным в отношении того, как их использовать. Таким образом, нет стандарта, рассказывающего нам, как делать что-либо в частности, помимо примеров.

  • В PEP есть раздел Подсказки приемлемого типа, в котором указано следующее:

    Аннотации должны быть допустимыми выражениями, которые оцениваются без привлечения исключений во время определения функции (но см. ниже для прямых ссылок).

    Аннотации следует сохранять просто, или инструменты статического анализа не могут интерпретировать значения. Например, вряд ли будут понятны динамически вычисляемые типы. (Это преднамеренно несколько неопределенное требование, конкретные включения и исключения могут быть добавлены к будущим версиям этого PEP, как этого требует обсуждение.)

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

  • Что касается исключений, PEP заявляет следующее:

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

  • Существует рекомендация по поводу типа комментариев, в которой у вас больше свободы, но даже в этом разделе не обсуждается, как для документирования отсутствия типа.

Есть одна вещь, которую вы могли бы попробовать в несколько иной ситуации, когда хотите намекнуть, что параметр или возвращаемое значение некоторой "нормальной" функции должно быть вызываемым, которое никогда не возвращается. Синтаксис Callable[[ArgTypes...] ReturnType], поэтому вы можете просто опустить возвращаемый тип, как в Callable[[ArgTypes...]]. Однако это не соответствует рекомендуемому синтаксису, поэтому, строго говоря, это не приемлемый тип намека. Шаблоны типов, скорее всего, захлебнутся.

Вывод: вы опережаете свое время. Это может быть разочаровывающим, но для вас тоже есть преимущество: вы все равно можете влиять на то, как аннотировать ненужные функции. Возможно, это послужит поводом для вас, чтобы принять участие в процессе стандартизации.: -)

У меня есть два предложения.

  • Позволяет исключить тип возвращаемого значения в подсказке Callable и разрешить тип чего-либо, который нужно переслать. Это приведет к следующему синтаксису:

    always_explode: Callable[[]]
    def always_explode():
        raise Exception('This function never returns because it always raises')
    
  • Введите нижний тип, например, в Haskell:

    def always_explode() -> ⊥:
        raise Exception('This function never returns because it always raises')
    

Эти два предложения могут быть объединены.