前面文章中,在定义爬虫函数时重点研究了*args、**kwargs两个参数的使用方法。
https://www.cnblogs.com/chen117/p/12952601.html
但在后面的学习中发现,当时对函数的理解还比较粗浅,经过更深入的学习——主要还是看了下面这篇知乎的狠贴,颠覆了之前了解的分类方式,所以专门写这篇总结一下。
https://www.zhihu.com/question/57726430
(当前最新的python版本是 3.8.3)
函数参数的作用是传递数据给函数使用。
一、参数有两种形式:形参、实参。
【实参】
调用函数时的参数,格式:
https://www.cnblogs.com/chen117/p/12952601.html
funcname(实参表) |
实参表由左到右就是简单的两个部分:
funcname(位置实参, 关键字实参) |
注意:这两种实参前后顺序是严格的,两个部分都可以缺省,但不能相互交错。(这确定了位置匹配的唯一性)
“关键字实参”可以摆脱位置约束。两种实际参数要共同覆盖所有没有默认值的形式参数。
例1:(关键字实参形式可以摆脱位置约束)
【形参】
定义函数时的参数。
# 函数定义,独立成块的代码,圆括号内是形式参数
def funcname(形参表): 函数体 |
形参从左到右可以分为五个部分:
def funcname(【限定位置形参】,【普通形参】,【特殊形参args】,【限定关键字形参】,【特殊形参kwargs】): pass |
其中两个特殊形参分别只能是0个或1个,其他形参可以是0个或多个。
尽管函数定义的形式如此丰富,但调用形式永远是简单的两部分——位置实参+关键字实参,与有无默认值无关。
二、形参类型:
1、限定位置形参:
纯位置形参。是为了限制开头几个参数只能按位置传递。(不能使用关键字实参形式)
Python从3.7开始,为某些内置函数定义了positional-only的形参。从Python 3.8开始,positional-only形参将可正式用于自定义函数中,它们必须放在形参表的最前面,并在后面使用斜杠/(独占一个参数位)与普通形参分隔。
例2.1:(a,b,c为限定位置形参,不能按关键字传递)
2、普通形参:
按最简形式定义出来的就是【普通形参】,它们是“位置、关键字兼容”的。
例2.2:( d为普通形参,可以按位置传递,也可以按关键字传递)
3、限定关键字形参(命名关键字参数)
(keyword-only)限制后面几个参数只能按关键字传递,这往往是因为后面几个形参名具有十分明显的含义,显式写出有利于可读性;或者后面几个形参随着版本更迭很可能发生变化,强制关键字形式有利于保证跨版本兼容性。
必须传入参数名,可以有缺省值。
例3.1:(d为限定关键字参数,只能按关键字传递)
例3.2:(当限定关键字参数d有缺省值时,可以省略)
4、特殊形参:*args
是一种可变参数,也叫元组参数。可以是元组也可以是列表序列。这种形式表示接受任意多个实际参数将其放到一个元组tuple中。
它位于普通形参之后,又只能接受位置实参。
例4:(虽然叫元组参数,但不要传入一个元组对象进去,需要 * 解封。)
5、特殊形参:**kwargs
也是一种可变参数,也叫关键字参数、字典参数,这种形式表示接受任意多个实际参数将其放到一个字典dict中。
关键字参数是一个由键值对组成的集合,允许通过变量名进行匹配,而不是位置。
例5:(虽然叫字典参数,但不能传入一个完整的字典对象,需要**解封)
6、混合参数
*args接收多余的位置实参,**kwargs接收多余的关键字实参。
*args 和 **kwargs 并不是 python 中的参数关键字,而是一种惯用写法。
例6.1:
例6.2:命名关键字参数不能与可变参数 *args 组合,可以与 **kwargs 组合。
四、特殊传参方法:
1、序列解包:
当你有个序列对象,想将其中元素解放出来作为调用函数的位置实参时,给它加个前缀*
即可。
例7:
2、字典解包:
当你有个字典对象,且其中的键都是合法的形参名时,想把其中的键值对解放出来作为调用函数的关键字参数,给它加个前缀**
即可。
例8:
五、参数传递基本法则:
将实际参数传递给形参的方式有两种:
值传递:实参为不可变对象,传递给形参后,形参的值改变,实参值不变。
引用传递:实参为可变对象,传递给形参后,形参的值改变,实参值改变。(传递地址)
当函数被调用时,解释器会查看传入的变量(内存地址)指向的类型,如果是可变类型的值,就按照引用传递变量;如果是一个非可变类型的值,就按照值传递变量。
尽管函数定义的形式如此丰富,但调用形式永远是简单的两部分——位置实参+关键字实参。注意这两个前后顺序是严格的,两个部分都可以缺省。
与有无默认值无关,位置实参永远按位置传递给*或*args之前对应的形参(即限定位置形参和普通形参),多余的位置实参传入*args(如果有的话);
关键字实参则匹配剩下的普通形参和限定关键字形参(非限定位置形参),多余的关键字实参则传入**kwargs(如果存在的话)。