Что означает → означает в определениях функций Python?

Недавно я заметил что-то интересное, глядя на Специфика грамматики Python 3.3:

funcdef: 'def' NAME parameters ['->' test] ':' suite

Дополнительный блок "стрелка" отсутствовал в Python 2, и я не мог найти никакой информации о его значении в Python 3. Оказывается, это правильный Python, и он принят интерпретатором:

def f(x) -> 123:
    return x

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

  • Я не могу проверить x здесь, на нем все еще undefined,
  • Независимо от того, что я помещаю после стрелки (например, 2 < 1), это не влияет на поведение функции.

Может ли кто-нибудь, привыкший к этому синтаксису, объяснить это?

Ответ 1

Это aa аннотация функции.

Более подробно Python 2.x имеет docstrings, которые позволяют присоединить строку метаданных к различным типам объектов. Это удивительно удобно, поэтому Python 3 расширяет эту функцию, позволяя вам прикреплять метаданные к функциям, описывающим их параметры и возвращаемые значения.

Нет предубежденного варианта использования, но PEP предлагает несколько. Один очень удобный способ - дать вам возможность комментировать параметры с их ожидаемыми типами; тогда было бы легко написать декоратор, который проверяет аннотации или принуждает аргументы к правильному типу. Другим является предоставление документации по параметрам вместо ее кодирования в docstring.

Ответ 2

Это аннотации функций, охватываемые PEP 3107. В частности, -> отмечает аннотацию функции возврата.

Примеры:

>>> def kinetic_energy(m:'in KG', v:'in M/S')->'Joules': 
...    return 1/2*m*v**2
... 
>>> kinetic_energy.__annotations__
{'return': 'Joules', 'v': 'in M/S', 'm': 'in KG'}

Аннотации - словари, поэтому вы можете сделать это:

>>> '{:,} {}'.format(kinetic_energy(20,3000),
      kinetic_energy.__annotations__['return'])
'90,000,000.0 Joules'

У вас также может быть структура данных python, а не просто строка:

>>> rd={'type':float,'units':'Joules','docstring':'Given mass and velocity returns kinetic energy in Joules'}
>>> def f()->rd:
...    pass
>>> f.__annotations__['return']['type']
<class 'float'>
>>> f.__annotations__['return']['units']
'Joules'
>>> f.__annotations__['return']['docstring']
'Given mass and velocity returns kinetic energy in Joules'

Или вы можете использовать атрибуты функции для проверки вызываемых значений:

def validate(func, locals):
    for var, test in func.__annotations__.items():
        value = locals[var]
        try: 
            pr=test.__name__+': '+test.__docstring__
        except AttributeError:
            pr=test.__name__   
        msg = '{}=={}; Test: {}'.format(var, value, pr)
        assert test(value), msg

def between(lo, hi):
    def _between(x):
            return lo <= x <= hi
    _between.__docstring__='must be between {} and {}'.format(lo,hi)       
    return _between

def f(x: between(3,10), y:lambda _y: isinstance(_y,int)):
    validate(f, locals())
    print(x,y)

Печать

>>> f(2,2) 
AssertionError: x==2; Test: _between: must be between 3 and 10
>>> f(3,2.1)
AssertionError: y==2.1; Test: <lambda>

Ответ 3

Как указывали другие ответы, символ -> используется как часть аннотаций функций. Однако в более поздних версиях Python >= 3.5 он имеет определенное значение.

PEP 3107 - Аннотации функций описывали спецификацию, определяя изменения грамматики, существование func.__annotations__, в котором они хранятся, и, тот факт, что он использует случай, остается открытым.

В Python 3.5, хотя PEP 484 - Type Hints придает одно значение: -> используется для указания тип, возвращаемый функцией. Также похоже, что это будет реализовано в будущих версиях, как описано в Что касается существующих применений аннотаций:

Самая быстрая мыслимая схема могла бы ввести молчаливую устаревание аннотаций не-типа-намека в 3.6, полное отклонение в 3.7 и объявить типы подсказок как единственно допустимое использование аннотаций в Python 3.8.

(Акцент мой)

На самом деле это не было реализовано как 3.6, насколько я могу судить, поэтому он может столкнуться с будущими версиями.

В соответствии с этим пример, который вы предоставили:

def f(x) -> 123:
    return x

будет запрещено в будущем (и в текущих версиях будет запутанно), его нужно будет изменить на:

def f(x) -> int:
    return x

чтобы эффективно описать, что функция f возвращает объект типа int.

Аннотации никоим образом не используются самим Python, они довольно много заполняют и игнорируют их. Это для сторонних библиотек для работы с ними.

Ответ 4

def function(arg)->123:

Это просто тип возвращаемого значения, в данном случае целое число не имеет значения, какое число вы пишете.

как Java:

public int function(int args){...}

Но для Python (как сказал Джим Фасаракис Хиллиард) возвращаемый тип - это просто подсказка, поэтому он предлагает возврат, но в любом случае позволяет возвращать другой тип, например, строку.

Ответ 5

Это самая бесполезная, глупая, бессмысленная, идиотская, высокомерная, подражательная, подражательная, глупая вещь, которую может сделать любой разработчик. НИКОГДА ни при каких обстоятельствах не добавляйте аннотации функций в ваш код. Это не добавляет абсолютно никакой ценности или вещества, чем беспорядок и/или путаницу. Единственное, что можно сделать, используя такую глупость, это то, что вы, как разработчик, представляете себя как один или все из вышеперечисленных синонимов.

Ответ 6

Python игнорирует это. В следующем коде:

def f(x) -> int:
    return int(x)

-> int просто говорит, что f() возвращает целое число. Он называется аннотацией возврата и доступен как f.__annotations__['return'].

Python также поддерживает аннотации параметров:

def f(x: float) -> int:
    return int(x)

: float говорит людям, которые читают программу (и некоторые сторонние библиотеки/программы, например, pylint), что x должен быть float. Он доступен как f.__annotations__['x'] и сам по себе не имеет никакого значения. Смотрите документацию для получения дополнительной информации:

https://docs.python.org/3/reference/compound_stmts.html#function-definitions https://www.python.org/dev/peps/pep-3107/