Что означает -> в определениях функций Python?
Недавно я заметил кое-что интересное, глядя на спецификацию грамматики Python 3.3:
funcdef: 'def' NAME parameters ['->' test] ':' suite
Необязательный блок "стрелка" отсутствовал в Python 2, и я не смог найти никакой информации относительно его значения в Python 3. Оказывается, это правильный Python, и он принят интерпретатором:
def f(x) -> 123:
return x
Я думал, что это может быть какой-то синтаксис предварительного условия, но:
- Я не могу проверить
x
здесь, это все еще не определено, - Неважно, что я ставлю после стрелки (например,
2 < 1
), это не влияет на поведение функции.
Может ли кто-нибудь, привыкший к этому синтаксису, объяснить это?
11 ответов
Более подробно, Python 2.x имеет строки документации, которые позволяют вам присоединять строку метаданных к различным типам объектов. Это удивительно удобно, поэтому Python 3 расширяет эту функцию, позволяя вам присоединять метаданные к функциям, описывающим их параметры и возвращаемые значения.
Там нет предвзятого варианта использования, но ПКП предлагает несколько. Один очень удобный способ - позволить вам аннотировать параметры с их ожидаемыми типами; тогда было бы легко написать декоратор, который проверяет аннотации или приводит аргументы к нужному типу. Другой - разрешить документацию по конкретным параметрам вместо того, чтобы кодировать ее в строку документации.
Это функциональные аннотации, описанные в 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>
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 https://www.python.org/dev/peps/pep-3107/
Как уже говорилось в других ответах, ->
Символ используется как часть аннотаций функций. В более поздних версиях Python >= 3.5
Тем не менее, он имеет определенное значение.
PEP 3107 - Аннотации функций описывают спецификацию, определяющую грамматические изменения, наличие func.__annotations__
в котором они хранятся, и тот факт, что это вариант использования по-прежнему открыт.
В питоне 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, он в значительной степени заполняет и игнорирует их. Работать с ними могут сторонние библиотеки.
Это означает тип результата, который возвращает функция, но он может быть None
.
Он широко распространен в современных библиотеках, ориентированных на Python 3.x.
Например, это есть в коде библиотеки pandas-profiling во многих местах например:
def get_description(self) -> dict:
def get_rejected_variables(self, threshold: float = 0.9) -> list:
def to_file(self, output_file: Path or str, silent: bool = True) -> None:
"""Write the report to a file.
def f(x) -> str:
return x+4
print(f(45))
# will give the result :
49
# or with other words '-> str' has NO effect to return type:
print(f(45).__class__)
<class 'int'>
def f(x) -> 123:
return x
Мое резюме:
Просто
->
вводится, чтобы разработчики могли дополнительно указать тип возвращаемого значения функции. См. Предложение по усовершенствованию Python 3107Это показатель того, как все может развиваться в будущем по мере того, как Python будет широко использоваться - указание на строгую типизацию - это мое личное наблюдение.
Вы также можете указать типы для аргументов. Указание типа возвращаемого значения функций и аргументов поможет уменьшить количество логических ошибок и улучшить улучшения кода.
Вы можете иметь выражения в качестве возвращаемого типа (как на уровне функции, так и на уровне параметра), а к результату выражений можно получить доступ через атрибут return объекта аннотаций. аннотации будут пустыми для выражения / возвращаемого значения для встроенных лямбда-функций.
def function(arg)->123:
Это просто тип возвращаемого значения, в данном случае целое число не имеет значения, какое число вы пишете.
как Java:
public int function(int args){...}
Но для Python (как сказал Джим Фасаракис Хиллиард) возвращаемый тип - это просто подсказка, поэтому он предлагает возврат, но в любом случае разрешает возвращать другой тип, например, строку.
-> введен в python3.
Проще говоря, содержимое после -> обозначает возвращаемый тип функции. Тип возврата не является обязательным.
он просто сообщает пользователю, что он ожидает ожидать или вернуть значение
funcname.__annotations__
распечатает детали
как
def function(name:str ,age:int) -> "printing the personal details ":
print(f"name is {name} age is {age}")
function("test",20)
print(function.__annotations__)
Выход
name is test age is 20
{'name': <class 'str'>, 'age': <class 'int'>, 'return': 'printing the personal details '}
даже когда вы возвращаете значения, он ничего не отображает.
Пожалуйста, обратитесь к спецификации PEP3107 . Это аннотации функций. В Python 2.x есть строки документации. Точно так же Python 3 представил использование -> в качестве аннотаций функций. Python использует их при создании документации.