参数注解

1、对函数的参数进行类型注解

2、对函数的返回值进行类型注解

3、只对函数参数做一个辅助说明,并不对函数参数进行类型检查

4、提供给第三方工具,做代码分析,发现隐藏BUG

5、函数注解的信息,保存在__annotations__属性中

def add(x: int, y: int, *args,  **kwargs) -> int:
    ret = x + y
    return ret


print(add.__annotations__)

out:
{'y': , 'return': , 'x': }  # 无序字典

Python 3.6引入

变量注解:  i: int = 3

业务应用:

函数参数的检查,一定是要函数外

函数应作为参数,传入到检查函数中

检查函数拿到函数传入的实际参数,与形参声明对比

__annotations__属性是一个字典,其中包括返回值类型的声明

假设要做位置参数的判断,无法和字典中的声明对应,要使用inspect模块

 

inspect模块

提供获取对象信息的函数,可以检查函数的类、类型检查

signature(callable),获取签名

签名包含了一个函数的信息,包括函数名,参数类型,它所在的类和名称空间及其他信息

 

Parameter对象

1、保存在元组中,是只读的

2、name,参数的名字

3、annotation,参数的注解,可能没有定义

4、default,参数的缺省值,可能没有定义

5、empty,特殊的类,用来标记default属性或者注解annotation属性的空值

6、kind,实参如何绑定到形参,就是形参的类型

POSITIONAL_ONLY,值必须是位置参数提供,Python没有实现,因为也是通过关键字传参

POSITIONAL_OR_KEYWORD,值可以作为关键字或者位置参数提供

VAR_POSITIONAL,可变位置参数,对应*args

KEYWORD_ONLY,keyword-only参数,对应*,或者*args后出现的非可变关键字参数

VAR_KEYWORD,可变关键字参数,对应**kwargs

import inspect


def add(x: int, y: int, *args, **kwargs) -> int:
    return x + y


sig = inspect.signature(add)
print(1, sig)
print(2, 'params : ', sig.parameters)  # OrderedDict
print(3, 'return : ', sig.return_annotation)
print(4, sig.parameters['y'])
print(5, sig.parameters['x'].annotation)
print(6, sig.parameters['args'])
print(7, sig.parameters['args'].annotation)
print(8, sig.parameters['kwargs'])
print(9, sig.parameters['kwargs'].annotation)


print(inspect.isfunction(add))   # 是否是函数
print(inspect.ismethod(add))  # 是否是类的方法
print(inspect.isgenerator(add))  # 是否是生成器对象
print(inspect.isgeneratorfunction(add))  # 是否是生成器函数
print(inspect.isclass(add))  # 是否是类
print(inspect.ismodule(inspect))  # 是否是模块
print(inspect.isbuiltin(print))   # 是否是内建对象


out:
1 (x:int, y:int, *args, **kwargs) -> int
2 params :  OrderedDict([('x', ), ('y', ), ('args', ), ('kwargs', )])
3 return :  
4 y:int
5 
6 *args
7 
8 **kwargs
9 
True
False
False
False
False
True
True
import inspect


def add(x, y: int=7, *args, z, t=10, **kwargs) -> int:
    return x + y


sig = inspect.signature(add)
print(sig)
print('params : ', sig.parameters)
print('return : ', sig.return_annotation)
print('~~~~~~~~~~~~~~~~')
for i, item in enumerate(sig.parameters.items()):
    print(item)
    name, param = item
    print(i+1, name, param, param.annotation, param.kind, param.default)
    print(param.default is param.empty, end='\n\n')

out:
(x, y:int=7, *args, z, t=10, **kwargs) -> int
params :  OrderedDict([('x', ), ('y', ), ('args', ), ('z', ), ('t', ), ('kwargs', )])
return :  
~~~~~~~~~~~~~~~~
('x', )
1 x x  POSITIONAL_OR_KEYWORD 
True

('y', )
2 y y:int=7  POSITIONAL_OR_KEYWORD 7
False

('args', )
3 args *args  VAR_POSITIONAL 
True

('z', )
4 z z  KEYWORD_ONLY 
True

('t', )
5 t t=10  KEYWORD_ONLY 10
False

('kwargs', )
6 kwargs **kwargs  VAR_KEYWORD 
True

 

业务应用:

参数有注解就要求实参类型和声明应该一致

import inspect


def check(fn):
    def wrapper(*args, **kwargs):
        print(args, kwargs)
        sig = inspect.signature(fn)   # 签名
        params = sig.parameters  # 有序字典
        values = list(params.values())
        print(values)
        # 位置参数处理
        for i, p in enumerate(args):
            print(i, p)
            print('===') if isinstance(p, values[i].annotation) or values[i].annotation is values[i].empty else print('xxx')
            print('##', values[i].annotation)
        # 关键字参数处理
        for k, v in kwargs.items():
            print(k, v)
            print('====') if isinstance(v, params[k].annotation) else print('xxxx')
            print('###', params[k].annotation)
        return fn(*args, **kwargs)
    return wrapper


@check
def add(x, y: int=7) -> int:  # 业务函数
    return x + y


print(add(5, 7))
print(add(y=4, x=9))



Out:
[, ]
0 5
===
## 
1 7
===
## 
12
[, ]
y 4
====
### 
x 9
xxxx
### 
13

out:
(5, 7) {}
[, ]
0 5
xxx
## 
1 7
===
## 
12
() {'x': 9, 'y': 4}
[, ]
x 9
xxxx
### 
y 4
====
### 
13

 

你可能感兴趣的:(个人笔记)