基于 Python 3 新增的函数注解(Function Annotations )语法实现参数类型检查功能

2016-01-06

python python 3 / Function Annotations

函数注解(Function Annotations)

函数注解语法 可以让你在定义函数的时候对参数和返回值添加注解:

def foobar(a: int, b: "it‘s b", c: str = 5) -> tuple:
    return a, b, c
  • a: int 这种是注解参数
  • c: str = 5 是注解有默认值的参数
  • -> tuple 是注解返回值。

注解的内容既可以是个类型也可以是个字符串,甚至表达式:

def foobar(a: 1+1) -> 2 * 2:
    return a

那么如何获取我们定义的函数注解呢?至少有两种办法:

  • __annotations__:

    >>> foobar.__annotations__
    {‘a‘: int, ‘b‘: "it‘s b", ‘c‘: str, ‘return‘: tuple}
    
  • inspect.signature:
    >>> import inspect
    >>> sig = inspect.signature(foobar)
    >>> # 获取函数参数
    >>> sig.paraments
    mappingproxy(OrderedDict([(‘a‘, <Parameter "a:int">), (‘b‘, <Parameter "b:"it‘s b"">), (‘c‘, <Parameter "c:str=5">)]))
    >>> # 获取函数参数注解
    >>> for k, v in sig.parameters.items():
            print(‘{k}: {a!r}‘.format(k=k, a=v.annotation))
    a: <class ‘int‘>
    b: "it‘s b"
    c: <class ‘str‘>
    >>> # 返回值注解
    >> sig.return_annotation
    tuple
    

既然可以得到函数中定义的注解,那么我们就可以用它进行参数类型检查了。

类型检查

Python 解释器并不会基于函数注解来自动进行类型检查,需要我们自己去实现类型检查功能:

>>> foobar.__annotations__
{‘a‘: int, ‘b‘: "it‘s b", ‘c‘: str, ‘return‘: tuple}

>>> foobar(a=‘a‘, b=2, c=3)
(‘a‘, 2, 3)

既然通过 inspect.signature 我们可以获取函数定义的参数的顺序以及函数注解, 那么我们就可以通过定义一个装饰器来检查传入函数的参数的类型是否跟函数注解相符, 这里实现的装饰器函数(check_type.py)如下:

# coding: utf8
import collections
import functools
import inspect

def check(func):
    msg = (‘Expected type {expected!r} for argument {argument}, ‘
           ‘but got type {got!r} with value {value!r}‘)
    # 获取函数定义的参数
    sig = inspect.signature(func)
    parameters = sig.parameters          # 参数有序字典
    arg_keys = tuple(parameters.keys())   # 参数名称

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        CheckItem = collections.namedtuple(‘CheckItem‘, (‘anno‘, ‘arg_name‘, ‘value‘))
        check_list = []

        # collect args   *args 传入的参数以及对应的函数参数注解
        for i, value in enumerate(args):
            arg_name = arg_keys[i]
            anno = parameters[arg_name].annotation
            check_list.append(CheckItem(anno, arg_name, value))

        # collect kwargs  **kwargs 传入的参数以及对应的函数参数注解
        for arg_name, value in kwargs.items():
           anno = parameters[arg_name].annotation
           check_list.append(CheckItem(anno, arg_name, value))

        # check type
        for item in check_list:
            if not isinstance(item.value, item.anno):
                error = msg.format(expected=item.anno, argument=item.arg_name,
                                   got=type(item.value), value=item.value)
                raise TypeError(error)

        return func(*args, **kwargs)

    return wrapper

下面来测试一下我们的装饰器:

@check
def foobar(a: int, b: str, c: float = 3.2) -> tuple:
    return a, b, c

顺序传参测试:

>>> foobar(1, ‘b‘)
(1, ‘b‘, 3.2)

>>> foobar(1, ‘b‘, 3.5)
(1, ‘b‘, 3.5)

>>> foobar(‘a‘, ‘b‘)
...
TypeError: Expected type <class ‘int‘> for argument a, but got type <class ‘str‘> with value ‘a

>>> foobar(1, 2)
...
TypeError: Expected type <class ‘str‘> for argument b, but got type <class ‘int‘> with value 2

>>> foobar(1, ‘b‘, 3)
...
TypeError: Expected type <class ‘float‘> for argument c, but got type <class ‘int‘> with value

关键字传参:

>>> foobar(b=‘b‘, a=2)
(2, ‘b‘, 3.2)
>>> foobar(b=‘b‘, a=2, c=3.5)
(2, ‘b‘, 3.5)

>>>foobar(a=‘foo‘, b=‘bar‘)
...
TypeError: Expected type <class ‘int‘> for argument a, but got type <class ‘str‘> with value ‘foo‘

>>> foobar(b=3, a=2)
...
TypeError: Expected type <class ‘str‘> for argument b, but got type <class ‘int‘> with value 3

>>> foobar(a=2, b=‘bar‘, c=3)
...
TypeError: Expected type <class ‘float‘> for argument c, but got type <class ‘int‘> with value

借助于 Function Annotations 一个简单的参数类型检查的装饰器就这样实现了。

原文地址:https://www.cnblogs.com/vincent-sh/p/12638649.html

时间: 2024-10-03 14:15:03

基于 Python 3 新增的函数注解(Function Annotations )语法实现参数类型检查功能的相关文章

python3 -&gt; 函数注释 Function Annotations

Python 3.X新增加了一个特性(Feature),叫作函数注释 Function Annotations 它的用途虽然不是语法级别的硬性要求,但是顾名思义,它可做为函数额外的注释来用. Python中普通的函数定义如下: def func(a, b, c): return a + b + c >>> func(1, 2, 3) 6 添加了函数注释的函数会变成如下形式: def func(a: 'spam', b: (1, 10), c: float) -> int: retu

[PY3]——函数——函数注解 | 实现类型检查功能

函数注解(Function Annotations)——> 可以在定义函数的时候对参数和返回值添加注解 写函数注解 #平时我们使用help()可以查看一个函数的说明,我们自己写的函数也可以提供这样的说明 #第一种方式:直接在函数内 '''写文本''' def add(x,y): '''x+y @:param x int @:param y int @return int ''' return x+y #print(help(add)) Help on function add in module

Python全栈__函数的有用信息、带参数的装饰器、多个装饰器装饰一个函数

1.函数的有用信息 代码1: 1 def login(username, password): 2 """ 3 此函数需要用户名,密码两个参数,完成的是登录的功能. 4 :return: True 登录成功. False登录失败. 5 """ 6 print(login.__name__) 7 print(login.__doc__) 8 print('登录成功...') 9 return True 10 11 print(login.__nam

Python标准库:内置函数map(function, iterable, ...)

本函数是把函数对象function作为函数,iterable对象的每一项作为参数,然后进行计算后输出迭代子iterator.如果函数对象function可以输入多参数,那么后面可以跟多个可迭代的对象.多个迭代对象时,以最短的对象为运行结果的判断. 例子: #map() x = range(10) print(list(map(hex, x))) print(list(map(lambda y : y * 2 + 1, x))) print(list(map(lambda y, z : y * 2

python中的自定义函数

1格式: deffunctionName(参数列表): 方法体 例子1: >>>def greet_user():         print("hello") >>>greet_user() hello 例子2: >>>def greet_user(username):  #username形参         print("hello,"+ username+"!") >>&g

【Python】Java程序员学习Python(五)— 函数的定义和使用

不想做一个待宰的羔羊!!!!要自己变得强大.... 函数的定义和使用放在最前边还是有原因的,现在语言趋于通用,基本类型基本都是那些,重点还是学习对象的使用方法,而最根本的还是方法的使用,因此优先介绍,方法的目的还是重用和封装 一.方法的定义 方法的定义使用关键词def来定义,定义格式如下: def 方法名(参数定义): 方法体 方法名:方法名的规范同变量名规范一样 参数定义:比较复杂,后面会进行讲解 冒号:这个类似于Java的{},必不可少 方法体:方法实现的功能在此定义即可 简单的例子: #定

python函数参数类型及其顺序

根据inspect模块官文文档中关于函数参数类型的相关说明,python函数参数共有五种类型,按顺序分别为:POSITIONAL_ONLY.POSITIONAL_OR_KEYWORD.VAR_POSITIONAL.KEYWORD_ONLY.VAR_KEYWORD.如图: POSITIONAL_ONLY:参数值必须以位置参数的形式传递.python没有明确的语法来定义POSITIONAL_ONLY类型的参数,但很多内建或扩展模块的函数中常常会接收这种参数类型,实际使用中不多见,这里暂不考虑. PO

python函数的可变和不可变参数

在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象.不可变类型:a = 1 #把1赋值给aa = 2 #把2赋值a这一过程中其实是重新创建新的值为2的对象a,原先指向1的变量a 被废弃了 可变类型:l = [1,2,3]l[0] = 99l这一过程中只是修改而已,l 指向这个列表的变量没有变化 def changeList(self,mylist): mylist.extend([1,2,3]) print(

介绍几款 Python 类型检查工具

微软在 Github 上开源了一个 Python 静态类型检查工具:pyright ,引起了社区内的多方关注. 微软在开源项目上的参与力度是越来越大了,不说收购 Github 这种大的战略野心,只说它家开源的 VS Code 编辑器,在猿界已经割粉无数,连我们 Python 圈的红人 Kenneth Reitz (多个开源项目的作者,包括 requests.requests-html.responder等)都对它赞不绝口. 如今开源的 Pyright ,口碑还不错,那我们就来看看它有啥本事,顺便