#python #python-3.x #function #type-hinting
#python #python-3.x #функция #подсказка типа
Вопрос:
Например
def function(param):
# do something
# return value
Используя подсказки по типу, я могу ознакомить пользователя с типом параметра param
и возвращаемым значением value
следующим образом:
def function(param : int)-> str:
# do something
# return value
Есть ли способ сообщить пользователю максимальное значение, которое может быть передано функции function
?
Комментарии:
1. Просто для ясности, когда вы говорите «пользователь», вы имеете в виду разработчика? если это так, вы могли бы просто сделать раннее исключение, если параметры превышают ожидаемые.
2. Пожалуйста, четко определите, чего вы хотите. «способом информирования пользователя» может быть что угодно: от аннотаций до проверок во время выполнения, до строк документации и случайного сообщения в блоге. Вы специально ищете подсказку типа, которая ограничена, или это просто пример, который вы попробовали и отклонили?
3. Да, я ищу подсказку по типу.
4. Можете ли вы добавить пример, подтверждающий ваши потребности??
Ответ №1:
TLDR: Используйте a Literal
, если допустимо очень мало значений, или a NewType
, если требуется программная проверка.
Literal
позволяет статически определять, какие значения разрешены.
from typing import literal
def digit_name(digit: Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) -> str: ...
digit_name(6) # valid
digit_name(12) # invalid
Обратите внимание, что, хотя Literal
технически это означает только эти значения, различные средства проверки типов допускают только фактические литералы для этих значений.
NewType
— Специализация с низкими накладными расходами определенного типа. Используйте его с привратником, который проверяет тип во время выполнения, чтобы отклонить недопустимые значения.
from typing import NewType
# Digit is a plain `int` at runtime, but a subclass for type checking
Digit = NewType('Digit', int)
def assert_digit(candidate: int) -> Digit:
assert 0 <= candidate <= 9 # assert can be optimised away with `-O` if the program is known to be correct
return Digit(candidate)
def digit_name(digit: Digit) -> str: ...
a_digit = assert_digit(3)
print(a_digit, 'is', digit_name(a_digit)) # valid
print(a_digit, 'is still', digit_name(a_digit)) # valid
print(3, 'is also still', digit_name(3)) # invalid
Этот шаблон позволяет установить границу между «любым значением» и «проверенным значением». Хотя гейткипер должен быть явно вызван и выполняет проверку во время выполнения, статическая проверка типа гарантирует, что гейткипер должен быть вызван, но достаточно одного раза.
Ответ №2:
Тип параметра может быть проверен (до определенной точки) компилятором или предварительным компилятором) во время разработки. Например, если вы вызываете функцию, используя некоторую переменную или выражение для параметра, компилятор может проверить, должно ли выражение иметь тот же тип, который ожидается для параметра.
Однако значение параметра может быть определено только во время выполнения, то есть когда программа запущена. Итак, нет, вы не можете получить подсказки типа, которые ограничивали бы параметр таким образом. Однако вы можете указать эту информацию в строке документа, чтобы пользователь мог узнать, проверили ли они, но компилятор или IDE не помогут.
Есть два других выхода:
- определите новый тип, который может иметь только тот диапазон значений, который вы готовы разрешить
- пусть функция вызывает исключение (во время выполнения), когда ей передается неправильное значение
Новый тип:
class Int0To9(int):
def __init__(self, value):
assert value in range(10)
super().__init__()
def my_func(x: Int0To9):
print(x)
# this one will work, but shows a type hint in a good IDE
my_func(1)
# this one will also work, but shows a type hint in a good IDE - this may be a problem, the value is out of range
my_func(10)
# this one works, as expected, no hints
my_func(Int0To9(2))
# this one raises an AssertionError, before the function is even called, as the Int0To9 cannot be instantiated
try:
my_func(Int0To9(11))
except AssertionError:
print('error, as expected (11)')
def my_safe_func(x: int):
assert x in range(10)
print(x)
# no problem
my_safe_func(3)
# This now raises an assertion error as well
try:
my_safe_func(12)
except AssertionError:
print('error, as expected (12)')
# no problem here still
my_safe_func(Int0To9(4))
def my_very_safe_func(x: Int0To9):
assert x in range(10)
print(x)
# this one gives a type hint and fails correctly
try:
my_very_safe_func(13)
except AssertionError:
print('error, as expected (13)')
# this one gives a type hint but succeeds if you run it, as expected
my_very_safe_func(5)
# only this one runs correctly without hints
my_very_safe_func(Int0To9(6))
# this one also fails, as before
try:
my_very_safe_func(Int0To9(14))
except AssertionError:
print('error, as expected (14)')
Результат:
1
10
2
error, as expected (11)
3
error, as expected (12)
4
error, as expected (13)
5
6
error, as expected (14)
Ответ №3:
Один из способов сделать это — использовать docstring, поэтому, когда пользователь вводит help (функция), он может видеть все, что вы написали в docstring.
Пример
def function(param : int)-> str:
"""
This function does this and returns this
:param param: integer with a maximum of 100
:return: anything
"""
# do something
# return value
итак, когда пользователь вводит
help(function)
он увидит справочное сообщение, подобное этому:
Help on function function in module __main__:
function(param: int) -> str
This function does this and returns this
:param param: integer with a maximum of 100
:return: anything
(END)
Примечание
Если пользователь использует функцию в Pycharm (я не знаю, работает ли она так же в других редакторах), он может увидеть меню справки, только наведя указатель мыши на название функции.