零基础学Python(第2版)
上QQ阅读APP看书,第一时间看更新

5.3.2 函数的参数

在C、C++中,参数的传递有值传递和引用传递两种方式。而Python中任何东西都是对象,所以参数只支持引用传递的方式。Python通过名称绑定的机制,把实际参数的值和形式参数的名称绑定在一起。即把形式参数传递到函数所在的局部命名空间中,形式参数和实际参数指向内存中同一个存储空间。

函数的参数支持默认值。当某个参数没有传递实际的值时,函数将使用默认参数计算。下面【例5-3】这段代码可以给arithmetic()的参数都提供一个默认值。

【例5-3.py】


01     # 函数的默认参数
02     def arithmetic(x=1, y=1, operator="+"):          # 定义arithmetic函数
03         result = {                                         # 定义result字典
04             "+" : x + y,
05             "-" : x - y,
06             "*" : x * y,
07             "/" : x / y
08         }
09         return result.get(operator)                 # 调用get方法返回计算结果
10
11     print (arithmetic(1, 2))
12     print (arithmetic(1, 2, "-"))
13     print (arithmetic(y=3, operator="-"))
14     print (arithmetic(x=4, operator="-"))
15     print (arithmetic(y=3, x=4, operator="-"))

【代码说明】

·第2行代码使用赋值表达式的方式定义参数的默认值。

·第11行代码,参数x、y的值分别赋值为1、2,参数operator使用默认值“+”。输出结果为“3”。

·第12行代码,提供了3个实际参数,这3个值将分别覆盖形式参数的默认值。输出结果为“-1”。

·第13行代码,指定参数y、operator的值。输出结果为“-2”。这里必须使用赋值表达式的方式传递参数;否则,Python解释器将误认为x=3、y="-"。因此下面的写法是错误的。


print (arithmetic(3, "-"))

·第14行代码,指定参数x、operator的值。输出结果为“3”。

·第15行代码,使用赋值表达式传递参数,可以颠倒参数列表的顺序。输出结果为“1”。

参数可以是变量,也可以是元组、列表等内置数据结构。下面【例5-4】这段代码实现列表作为参数传递。

【例5-4.py】


01     # 列表作为参数传递
02     def arithmetic(args=[], operator="+"):
03         x = args[0]
04         y = args[1]
05         result = {
06             "+" : x + y,
07             "-" : x - y,
08             "*" : x * y,
09             "/" : x / y
10         }
11     return result.get(operator)
12     print (arithmetic([1, 2]))

【代码说明】

·第2行代码把参数x、y合并为一个参数,通过args列表传递x、y的值。

·第3、4行代码,从列表中取出参数值分别赋值给变量x、y。

·第12行代码,把列表[1,2]传递给arithmetic()。输出结果为“3”。

由于参数实现了名称绑定的机制,在使用默认参数时,可能会出现预期之外的结果。


01     def app(args=[]):
02         args.append(0)
03         print (args)
04
05     app()
06     app([1])
07     app()

【代码说明】

·第1行代码定义了一个app()函数,参数是一个默认的列表。

·第2行代码在列表中追加一个元素0。

·第5行代码调用app(),使用默认的列表。输出结果为“[0]”。

·第6行代码,传递了一个列表[1],app()中追加一个元素1。输出结果为“[1,0]”。

·第7行代码再次调用app(),此时使用的列表还是第一次调用的args,因此args在原有的基础上将再次追加一个元素0。输出结果为“[0,0]”。

为了避免这个问题,可以在append()中添加一个条件判断语句。如果列表args中没有任何元素,则先把args列表置空,然后再添加元素。下面通过【例5-5】的代码实现。

【例5-5.py】


01     def app1(args=[]):
02         if len(args) <= 0:
03             args = []
04         args.append(0)
05         print (args)
06
07     app1()
08     app1([1])
09     app1()

【代码说明】

·第2行代码使用len()判断列表args的长度是否大于0。如果小于等于0,则把args置为空列表,即取消了函数参数的绑定。

·第4行代码在列表中追加一个元素0。

·第7行代码调用app1(),使用默认的列表。输出结果为“[0]”。

·第8行代码,传递了一个列表[1],app1()中追加一个元素0。输出结果为“[1,0]”。

·第9行代码调用app1(),通过len(args)的判断,取消了参数的名字绑定。输出结果为“[0]”。

在开发中,常常需要传递可变长度的参数。在函数的参数前使用标识符“*”可以实现这个要求。“*”可以引用元组,把多个参数组合到一个元组中。


01     # 传递可变参数
02     def func1(*args):
03         print(args)
04     func1(1, 2, 3)

【代码说明】

·第2行代码,在参数args前使用标识符“*”。

·第3行代码输出参数的值,由于参数使用了“*args”的形式,因此传入的实际参数被“打包”到一个元组中,输出结果为“(1,2,3)”。

·第4行代码调用函数func1()。其中的参数“1”、“2”、“3”成为args元组的元素。

Python还提供另一个标识符“**”。在形式参数前面添加“**”,可以引用一个字典,根据实际参数的赋值表达式生成字典。例如,下面这段代码实现了在一个字典中匹配元组的元素。定义函数时,设计两个参数:一个是待匹配的元组,表示为“*t”;另一个是字典,表示为“*d”。函数调用时,实际参数分成两部分:一部分参数是若干个数字或字符串,另一部分参数是赋值表达式,如图5-4所示。下面通过【例5-6】的代码实现。

图5-4 “*”、“**”与实际参数的对应关系

【例5-6.py】


01     # 传递可变参数
02     def search(*t, **d):           # 定义search函数
03         keys = d.keys()
04         values = d.values()
05         print(keys)
06         print (values)
07         for arg in t:
08             for key in keys:
09                 if arg == key:
10                     print ("find:",d[key])
11
12     search("one", "three", one="1",two="2",three="3")          # 调用search函数

【代码说明】

·第2行代码中的“*t”与第12行代码中的“one”、“three”对应。“one”、“three”组成一个元组t。“**d”与“one="1",two="2",three="3"”对应,生成一个字典{one:"1",two:"2",three:"3"}。

·第5行代码输出结果:


dict_keys(['one', 'two', 'three'])

·第6行代码输出结果:


dict_values(['1', '2', '3'])

·第7行到第10行代码在字典d中查找元组t中的值。如果找到,则输出。输出结果如下所示。


find: 1
find: 3

注意 “*”必须写在“**”的前面,这是语法规定。