Как ограничить допустимые значения, которые могут быть переданы параметру метода (Использование подсказок типов для разрешения статического анализа кода) - PullRequest
1 голос
/ 22 апреля 2019

В Python 3 я хочу ограничить допустимые значения, передаваемые этому методу:

my_request(protocol_type, url)

Используя тип подсказки, я могу написать:

my_request(protocol_type: str, url: str)

поэтому протокол и URL-адрес ограничены строками, но как я могу проверить, что protocol_type принимает только ограниченный набор значений, например 'http' и 'https'?

Ответы [ 4 ]

3 голосов
/ 22 апреля 2019

Одним из способов является написание кода в методе для проверки того, что переданное значение является 'http' или 'https', что-то в строках:

if (protocol_type == 'http') or (protocol_type == 'https'):
  Do Something
else:
  Throw an exception

, которое будет хорошо работать во время выполнения,но не дает указания на проблему при написании кода.

Вот почему я предпочитаю использовать Enum и механизм подсказки типов, которые реализуют Pycharm и mypy.

Для примера коданиже вы получите предупреждение в Pycharm из его проверки кода, см. прикрепленный скриншот.На снимке экрана показано, что если вы введете значение, которое не является enum, вы получите предупреждение "Ожидаемый тип: ...".

Код:

"""Test of ENUM"""

from enum import Enum


class ProtocolEnum(Enum):
    """
    ENUM to hold the allowed values for protocol
    """
    HTTP: str = 'http'
    HTTPS: str = 'https'


def try_protocol_enum(protocol: ProtocolEnum) -> None:
    """
    Test of ProtocolEnum
    :rtype: None
    :param protocol: a ProtocolEnum value allows for HTTP or HTTPS only
    :return:
    """
    print(type(protocol))
    print(protocol.value)
    print(protocol.name)


try_protocol_enum(ProtocolEnum.HTTP)

try_protocol_enum('https')

Вывод:

<enum 'ProtocolEnum'>
http
HTTP

Warnings issued by Pycharm Static Code Analysis - Code Inspection

1 голос
/ 22 апреля 2019

Используйте оператор if, который вызывает исключение, если protocol_type отсутствует в списке допустимых значений:

allowed_protocols = ['http', 'https']
if protocol_type not in allowed_protocols:
    raise ValueError()
1 голос
/ 22 апреля 2019

Вы можете просто проверить правильность ввода в функции:

def my_request(protocol_type: str, url: str):
    if protocol_type in ('http', 'https'):
        # Do x
    else:
        return 'Invalid Input'  # or raise an error
1 голос
/ 22 апреля 2019

Я думаю, вы можете использовать декораторы, у меня похожая ситуация, но я хотел проверить типы параметров:

def accepts(*types):
    """
    Enforce parameter types for function
    Modified from https://stackoverflow.com/questions/15299878/how-to-use-python-decorators-to-check-function-arguments
    :param types: int, (int,float), if False, None or [] will be skipped
    """
    def check_accepts(f):
        def new_f(*args, **kwds):
            for (a, t) in zip(args, types):
                if t:
                    assert isinstance(a, t), \
                           "arg %r does not match %s" % (a, t)
            return f(*args, **kwds)
        new_f.func_name = f.__name__
        return new_f
    return check_accepts

А затем использовать как:

@accepts(Decimal)
def calculate_price(monthly_item_price):
    ...

Вы можете изменитьмой декоратор для достижения того, что вы хотите.

...