一,函数定义的弊端:
1)Python是动态语言,变量随时可以被赋值,且能赋值为不同的类型。
2)Python不是静态编译型语言,变量类型是运行器决定的
3)动态语言很灵活,但这也是其弊端:
- def add(x + y):
- return x + y
- print(add(4,5))
- print(add('hello','world'))
- add(4,'hello') #这句显然是错的
首先,难发现,由于不做任何类型检查,直到运行期问题菜显现出来,或线上运行时才发现问题;
其次,难使用,函数使用者看到函数的时候并不知道你的函数的设计,并不知道应该传入什么类型的数据
二,如何解决这种弊端?
1)增加文档Documentation String:
这只是一个惯例,并不是强制标准,不能要求程序员一定为函数提供说明文档,并且函数定义更新了,文档未必同步更
- def add(x,y):
- '''
- :param x:int
- :param y:int
- :return: int
- '''
- return x + y
- print(help(add))
2)函数注解
- def add(x:int,y:int)->int:
- '''
- :param x:int
- :param y:int
- :return: int
- '''
- return x + y
- print(help(add))
- print(add(4,5))
- print(add('func','tion'))
定义:
Python 3.5引入;对函数的参数进行类型注解;对函数的返回值进行类型注解;只对函数参数做一个辅助的说明,并不对函数参数进行类型检查;提供给第三方工具,做代码分析,发现隐藏BUG;函数的注解信息保存在__annotations__属性中;
变量注解在Python 3.6中引入: i :int = 3
3) inspect模块:
![]()
![]()
![]()
![]()
4)业务应用:函数参数类型的检查
思路:1,函数参数的检查,一定是在函数外;
2,函数应该作为参数,传入到检查函数中;
3,检查函数拿到函数传入的实际参数,与形参声明对比;
4,__annotations__属性是一个字典,其中包括返回值类型的声明.假设要做位置参数的判断,无法和字典中的声明对应,使用inspect模块提供获取对象信息的函数,可以检查函数和类,类型检查
- import inspect
- import functools
- def dect(fn):
- @functools.wraps(fn)
- def _dect(*args,**kwargs):
- sig = inspect.signature(fn)
- params = sig.parameters #有序字典
- keys = list(params.keys())
- values = [_ for _ in params.values()]
- for i,m in enumerate(args): #args用tuple包装二元组的方式保存位置参数
- if values[i].annotation is not inspect._empty and isinstance(m,values[i].annotation): #和注解进行比较
- print(keys[i],'==', m)
- for k,v in kwargs.items():
- if paras[k].annotation is not inspect._empty and isinstance(v,params[k].annotation): #业务需求应该是没有注解就不比较了
- print(k,'===',v)
- ret = fn(*args,**kwargs)
- return ret
- return _dect
- @dect
- def add(x,y:int =7) -> int: #add = dect(add)
- return x + y
- add(4,5)
文章知识点与官方知识档案匹配,可进一步学习相关知识
Python入门技能树高级教程函数416654 人正在系统学习中
评论记录:
回复评论: