zoukankan      html  css  js  c++  java
  • 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类型,如果定义了类型,就是指定的类型,时间有限,这篇就讲到这里面了,下一篇写一下注解,因为我对注解也不是特别了解,需要深入了解以后才能写东西。

  • 相关阅读:
    sky A800s手机恢复出厂设置操作
    SlimDx绘制点图元的问题
    自定义Token的CAS登录
    未来谁才是移动互联网的入口?
    [Oracle]Sqlplus连接成功,但pl/sql连接不成功,提示“ora-12145:无法解析指定的连接标识符”
    memcached分布式内存系统
    Android下结束进程的方法
    博客搬家啦~
    NOIp2013火柴排队
    NOIp2014 T2联合权值
  • 原文地址:https://www.cnblogs.com/dutu/p/10917217.html
Copyright © 2011-2022 走看看