前面文章中,在定义爬虫函数时重点研究了*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(如果存在的话)。

posted on 2020-05-29 00:16  chen117  阅读(1034)  评论(0编辑  收藏  举报