python的函数参数基础(可能和别人讲的不一样,稍微深入一点)
Posted dutu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python的函数参数基础(可能和别人讲的不一样,稍微深入一点)相关的知识,希望对你有一定的参考价值。
先让我说几句废话,函数(java里面叫方法)可能是我们了解python以后最基础的东西了(除了数据结构),写了无数个函数,你真的了解python的函数的设计逻辑以及思想吗?
先上一小段我们最经常写的代码,我简单剖析一下:
1 def func_test(x,y,z): 2 print(x,y,z) 3 return None 4 5 if __name__ == ‘__main__‘: 6 func_test(1,y=2,z=3)
上面这个代码很简单,就是定义了一个函数,让这个函数打印传入的三个参数,并且返回一个None,但是我在调用的时候的传参方式很别扭,第一个我没有写x=1,而是直接用的1,第二个参数我是用的y=2,但是第三个我也用的y=3,如果你改成下面这样:
1 def func_test(x,y,z): 2 print(x,y,z) 3 return None 4 5 if __name__ == ‘__main__‘: 6 func_test(1,y=2,3)
那么编译器一定会报错,究其原因,是因为python的传参问题,因为python的函数接收参数列表方式有两种,第一种是*args(list),第二种是**kwargs(字典),某些角度上来说,第一个是一位数组,第二个是二维数组,但是如果你在一维数组中间,比如y的这个位置,使用了二位数组的传参方式y=2,那么第三个参数,也必须使用二位数组的传参方式,否则就会报错,但是,如果都不用y=这种方式,而用下面的方式,则不会报错:
1 def func_test(x,y,z): 2 print(x,y,z) 3 return None 4 5 if __name__ == ‘__main__‘: 6 func_test(1,2,3)
剖析一下第二段代码,因为如果你在参数列表中间使用y=2,编译器会跳过这个参数,那么*args里面的参数列表就少了一个,原本*args里面应该是三个参数,如果跳过一个变成两个参数,那么这两个参数第一个肯定赋给x了,但是第二个应该赋给y还是赋给z,因为y=2被**kwargs捕获了,所以为了避免混淆,编译器第二个参数以及后面的参数必须被**kwargs捕获。
接下来在加一个东西,就是参数列表的类型,python是可以定义参数列表的类型的,但是由于是动态语言,所以一般情况下,python不会有严格的参数校验,但是有时候,我们还有相关的需求,所以这个时候就需要下面这种定义方式:
1 def func_test(x,y:str,z:int,i:list,j:dict,a:bool): 2 print(x,y,z,i,j,a) 3 return None 4 5 if __name__ == ‘__main__‘: 6 func_test(1,‘2‘,3,[1,2],{2:3},True)
看起来有点乱,大概的意思就是x不限定类型,y是str类型,z是int类型,是list类型,j是dict类型,a是bool类型,但是由于python不强制限制类型,最多会在pycharm里面提示你传的参数类型不对,编译器并不会强校验,这个时候,如果某些函数想要有这个功能就要加一个python的魔法小代码了,注解,我这段代码没有加强校验,只会打印,如果加,可以加一个assert:
1 def check(fn): 2 @functools.wraps(fn) 3 def wrapper(*args, **kwargs): 4 sig = inspect.signature(fn) #截取函数签名 5 param_map = sig.parameters #获取参数列表的字典 6 param_list = list(param_map.values()) #获取参数列表 7 print(type(param_list[0])) 8 for i, v in enumerate(args): 9 param = param_list[i] 10 if param.annotation is not param.empty and not isinstance(v, param.annotation): 11 print(param.name,":",v, "!=", param_list[i].annotation) 12 for k, v in kwargs.items(): 13 if param_map[k].annotation is not inspect._empty and not isinstance(v, param_map[k].annotation): 14 print(k,‘:‘, v, ‘!=‘, param_map[k].annotation) 15 return fn(*args, **kwargs) 16 return wrapper 17 18 @check 19 def func_test(x,y:str,z:int,i:list,j:dict,a:bool): 20 print(x,y,z,i,j,a) 21 return None 22 23 if __name__ == ‘__main__‘: 24 func_test(1,2,3,[1,2],{2:3},a=0)
param的类是inspect.Parameter,具体参数可以自行百度,篇幅有限就不写太多了,ParamTer中有annotation这个变量,如果不指定paramter的类型,那么它就是inspect._empty类型,如果定义了类型,就是指定的类型,时间有限,这篇就讲到这里面了,下一篇写一下注解,因为我对注解也不是特别了解,需要深入了解以后才能写东西。
以上是关于python的函数参数基础(可能和别人讲的不一样,稍微深入一点)的主要内容,如果未能解决你的问题,请参考以下文章