如果传递给注释函数的参数类型与指定的不匹配,是否可以使 python 抛出错误?

Is it possible to make python throw errors if the type of the argument passed to the annotated function doesn't match the one specified?

python3.5 中的一项新功能是类型提示。例如下面的代码现在有效:

def greeting(name: str) -> str:
    return 'Hello ' + name

但是,据我了解,它本身不检查任何内容,而且其解释方式与此完全相同:

def greeting(name):
    return 'Hello ' + name

并且主要是为了帮助静态分析器(并使代码更容易理解)而实现的。但是,当将无效类型的参数传递给带有注释参数的函数时,是否有(或计划在将来实现)任何方式(可能通过使用某些第三方库)使 python 抛出错误类型(仅使用类型提示语法)?

我认为最简单的方法是检查类型:

def greeting(name):
    if not isinstance(name, str):
        raise TypeError('Expected str; got %s' % type(name).__name__)
    return 'Hello ' + name

类型提示实现 PEP 0484 明确列为 非目标 :

While the proposed typing module will contain some building blocks for runtime type checking -- in particular the get_type_hints() function -- third party packages would have to be developed to implement specific runtime type checking functionality, for example using decorators or metaclasses. Using type hints for performance optimizations is left as an exercise for the reader.

由此看来,Python 开发人员似乎没有计划添加您寻求的功能。引用提到了装饰器,这似乎是可行的方法。从概念上看,这似乎很简单——装饰器将在要装饰的函数上使用 get_type_hints() 并遍历参数,根据任何提示检查它们的类型,如果存在冲突则抛出错误或简单地传递函数的参数。这类似于 pzelasko 的回答,但装饰器使用提示自动处理样板代码。最简单的方法是简单地审查参数,尽管你也应该能够制作一个装饰器,如果 return 类型与提示冲突,它会引发错误。我还没有 Python 3.5,也没有时间研究它——但对于想要同时了解装饰器和类型提示的人来说,这似乎是一个很好的学习练习。或许您可以成为 PEP 提到的 "third parties" 之一。

可以使用库 https://github.com/h2oai/typesentry 在运行时执行此操作。

自 python 3.7 发布以来,可以使用 functools.singledispatch.

执行此操作
from functools import singledispatch

@singledispatch
def greet(arg: object):
    raise NotImplementedError(f"Don't know how to greet {type(arg)}")

@greet.register
def _(arg: str):
     print(f"Hello, {arg}!")
    
@greet.register
def _(arg: int):
    print(', '.join("Hello" for _ in range(arg)), "!")

greet("Bob")          # string implementation is called — prints "Hello, Bob!"
greet(4)              # int implementation is called — prints "Hello, Hello, Hello, Hello!"
greet(["Alice, Bob"]) # no list implementation, so falls back to the base implementation — will raise an exception

在上面的示例中,注册了一个将引发 NotImplementedError 的基本实现。这是在 none 其他实现合适时返回的“后备”实现。

根据基本实现的定义,可以注册任意数量的特定于类型的实现,如示例所示——函数的行为完全不同,具体取决于提供给它的参数的类型,并且@singledispatch 方法使用类型注释来注册具有特定 type.

的函数的特定实现

singledispatch 函数可以有任意数量的参数,但只有第一个参数的类型注释与调用的实现相关。

如果使用Python3.6注解,可以使用typeguard装饰器: https://typeguard.readthedocs.io/en/latest/userguide.html#using-the-decorator

注意:这应该只是一个“调试”或“测试”工具,而不是生产工具。 因此,他们建议在不生产的情况下将 -O 选项添加到 python 到 运行。

它不会自动检查内联变量注释,只检查函数参数、函数 return 和对象类型。

来自文档:

from typeguard import typechecked

@typechecked
def some_function(a: int, b: float, c: str, *args: str) -> bool:
    ...
    return retval

@typechecked
class SomeClass:
    # All type annotated methods (including static and class methods and properties)
    # are type checked.
    # Does not apply to inner classes!
    def method(x: int) -> int:
        ...

您也可以将此自动化到所有功能:

with install_import_hook('myapp'):
    from myapp import some_module