如何限制可以传递给方法参数的允许值(使用类型提示进行静态代码分析)

时间:2019-04-22 09:30:50

标签: python enums enumeration type-hinting

在Python 3中,我想限制传递给此方法的允许值:

my_request(protocol_type, url)

使用类型提示,我可以写:

my_request(protocol_type: str, url: str)

因此协议和网址仅限于字符串,但是如何验证protocol_type仅接受有限的一组值,例如'http''https'

4 个答案:

答案 0 :(得分:3)

一种方法是在该方法中编写代码以验证传入的值是“ http”还是“ https”,类似于以下行:

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

在运行时可以很好地工作,但是在编写代码时并不能提供问题的提示。

这就是为什么我更喜欢使用Enum和Pycharm和mypy实现的类型提示机制的原因。

对于下面的代码示例,您将在Pycharm的代码检查中收到警告,请参阅随附的屏幕截图。 屏幕截图显示,如果您输入的值不是枚举,则会收到“预期类型:...”警告。

代码:

"""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 :(得分:1)

我猜您可以使用装饰器,情况类似,但我想验证参数类型:

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):
    ...

您可以修改我的装饰器以实现您想要的。

答案 2 :(得分:1)

如果protocol_type不在允许值列表中,请使用if语句引发异常:

allowed_protocols = ['http', 'https']
if protocol_type not in allowed_protocols:
    raise ValueError()

答案 3 :(得分:1)

您可以仅在函数中检查输入是否正确:

def my_request(protocol_type: str, url: str):
    if protocol_type in ('http', 'https'):
        # Do x
    else:
        return 'Invalid Input'  # or raise an error