【问题标题】:Type hinting in Python 2Python 2 中的类型提示
【发布时间】:2016-05-15 19:30:46
【问题描述】:

PEP 484 中,类型提示已添加到 Python 3 中,其中包含 typing 模块。有没有办法在 Python 2 中做到这一点?我能想到的只是将装饰器添加到检查类型的方法中,但这会在运行时失败,并且不会像提示允许的那样更早被捕获。

【问题讨论】:

    标签: python python-2.7 types type-hinting python-typing


    【解决方案1】:

    根据定义类型提示的 PEP 484 中的Suggested syntax for Python 2.7 and straddling code,有一种与 Python 2.7 兼容的替代语法。但是它不是强制性的,所以我不知道它的支持程度,但引用 PEP:

    某些工具可能希望在必须与 Python 2.7 兼容的代码中支持类型注释。为此,此 PEP 有一个建议的(但不是强制性的)扩展,其中函数注释放置在 # 类型:注释中。这样的注释必须紧跟在函数头之后(在文档字符串之前)。示例:以下 Python 3 代码:

    def embezzle(self, account: str, funds: int = 1000000, *fake_receipts: str) -> None:
        """Embezzle funds from account using fake receipts."""
        <code goes here>
    

    等价于:

    def embezzle(self, account, funds=1000000, *fake_receipts):
        # type: (str, int, *str) -> None
        """Embezzle funds from account using fake receipts."""
        <code goes here>
    

    有关mypy 的支持,请参阅Type checking Python 2 code

    【讨论】:

    • 嗯好的,应该进一步阅读文档。您知道目前是否有任何工具支持此功能?不确定它是否只是一个标准,或者是否已经实现了实际的工具。
    • 根据 PyCharm “PyCharm 使用 PEP 484 定义的类型模块支持函数注释中的类型提示和类型 cmets。”对 TYPE COMMENTS 的引用清楚地表明它应该被支持。我不在这台计算机上使用 pyCharm,所以我现在无法检查它。编辑:链接到 pycharm:jetbrains.com/pycharm/help/…
    • 谢谢,还发现 Emacs Jedi 也可以使用它。
    • 有点跑题了:也许你知道我如何在 Python 2 中提取这种类型注释?它不包含在__doc__ attr 中,__annotations__ attr 在 Python 2 中不可用。
    • 这是否也适用于早期版本的 Python 3?
    【解决方案2】:

    此时推荐的和 python3 兼容的方法是遵循 python2 到 3 指南:http://python-future.org/func_annotations.html

    def embezzle(self, account: str, funds: int = 1000000, *fake_receipts: str) -> None:
        """Embezzle funds from account using fake receipts."""
        pass
    

    变成:

    def embezzle(self, account, funds = 1000000, *fake_receipts):
        """Embezzle funds from account using fake receipts."""
        pass
    embezzle.__annotations__ = {'account': str, 'funds': int, 'fake_receipts': str, 'return': None}
    

    【讨论】:

    • 这不适用于ListSet等非文字类型
    【解决方案3】:

    这是我编写的一个函数,用于解析 Python 2 类型注释并获取输入类型和返回类型的元组。处理类型库中的复杂类型定义(Any、Optional、List 等)需要做一些工作:

    class InvalidTypeHint(Exception):
        pass    
    
    PYTHON_2_TYPE_HINT_REGEX = "\s*#\s*type:\s*(\(.+\))\s*->\s*(.+)\s*"
    
    def parse_python_2_type_hint(typehint_string):
        # type: (str) -> (tuple, type)
        pattern = re.compile(PYTHON_2_TYPE_HINT_REGEX)
        search_results = pattern.search(typehint_string)
        if not search_results:
            raise InvalidTypeHint('%s does not match type hint spec regex %s' % (typehint_string, PYTHON_2_TYPE_HINT_REGEX))
        arg_types_str = search_results.group(1)
        return_type_str = search_results.group(2)
        try:
            arg_types_tuple = eval(arg_types_str)
            assert isinstance(arg_types_tuple, tuple)
            return_type = eval(return_type_str)
            assert isinstance(return_type, type)
        except Exception as e:
            raise InvalidTypeHint(e)
        return arg_types_tuple, return_type
    
    
    def parse_arg_types_for_callable(func):
        # type:(callable)->tuple
        """
    
        :param func:
        :return: list of parameter types if successfully parsed, else None
        """
    
        # todo make this compatible with python 3 type hints
        # python 2.7 type hint
        source_lines = inspect.getsource(func).split("\n")
        def_statements = 0
        for source_line in source_lines:
            try:
                arg_types_tuple, return_type = parse_python_2_type_hint(source_line)
                return arg_types_tuple
            except InvalidTypeHint:
                if source_line.strip().startswith("def "):
                    def_statements += 1
                if def_statements > 1:
                    return None
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-14
      • 2022-09-29
      • 1970-01-01
      • 2021-11-25
      • 2021-10-19
      • 1970-01-01
      • 2018-08-31
      • 2018-05-12
      相关资源
      最近更新 更多