不定长参数
在前面的函数介绍中,一个形参只能接收一个实参,除此之外,函数形参可以接收不定个数的实参,即用户可以给函数提供可变长度的参数,这可以通过在参数前面使用*来实现,如下所示。
1 def mySum(a = 0, b = 0, *args):
2 print(a, b, args)
3 sum = a + b
4 for n in args:
5 sum += n
6 return sum
7 print(mySum(2, 3))
8 print(mySum(2, 3, 4))
9 print(mySum(2, 3, 4, 5))
运行结果如下图所示。

在上例中,第1行中加了星号的变量args会存放所有未命名的变量参数,其数据类型为元组。第7行调用函数时传入2个实参,分别对应形参a与b,此时args是一个空元组。第8行调用函数时传入3个参数,此时将第3个参数添加到元组中。第9行调用函数时传入4个参数,此时将后两个参数添加到元组中。
此外,不定长参数还可以接受关键参数并将其存放到字典中,这时需要使用**来实现,如下所示。
1 def mySum(a = 0, b = 0, *args1, **args2):
2 print(a, b, args1, args2)
3 sum = a + b
4 for n in args1: # 遍历元组
5 sum += n
6 for key in args2: # 遍历字典
7 sum += args2[key]
8 return sum
9 print(mySum(2, 3, 4, 5))
10 print(mySum(2, 3, c = 4, d = 5))
11 print(mySum(2, 3, 4, 5, c = 6, d = 7))
运行结果如下图所示。

在上例中,第1行中加了两个星号的变量args2会存放关键参数,其数据类型为字典。第9行调用函数时传入4个实参,第3个参数与第4个参数添加到元组args1中,此时args2是一个空字典。第10行调用函数时传入4个参数,第3个参数与第4个参数添加到字典args2中,此时args1是一个空元组。第11行调用函数时传入6个参数,第3个参数与第4个参数添加到元组args1中,第5个参数与第6个参数添加到字典args2中。
此外,通过*还可以进行相反的操作,如下所示。
1 def mySum(a, b, c):
2 return a + b + c
3 tuple1 = (2, 3, 4)
4 print(mySum(*tuple1))
5 list1 = [2, 3, 4]
6 print(mySum(*list1))
运行结果如上图所示。

在上例中,第4行在调用函数时在元组tuple1前加上星号,此时将tuple1中的3个元素分别传递给形参a、b、c,此外,还可以在列表前加星号,如第6行。
另外,通过**可以将字典转换为关键参数,如下所示。
1 def mySum(a, b, c):
2 return a + b + c
3 dict1 = {'a':2, 'b':3, 'c':4}
4 print(mySum(**dict1))
运行结果如下图所示。

在上例中,第4行在调用函数时在字典dict1前加上两个星号,此时将dict1中的3个键值对分别转换为关键参数。
此外,需注意上述两种方式的传递顺序,如下所示。
1 def mySum(a, b, c):
2 return a + b + c
3 print(mySum(*(2,),**{'b':3, 'c':4}))
4 # print(mySum(**{'b':3, 'c':4}, *(2,))) 错误写法
运行结果如下图所示。

在上例中,第3行调用mySum()函数时,第一个参数在元组前加,第二个参数在字典前加*,此时形参中a、b、c的值分别为2、3、4。第4行交换参数的位置,则会发生错误。
传递不可变与可变对象
在Python中,数字、字符串与元组是不可变类型,而列表、字典是可变类型,两者区别如下:
- 不可变类型:该类型的对象所代表的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。
- 可变类型:该类型的对象所代表的值可以被改变。变量改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的出地址,通俗点说就是原地改变。
接下来演示调用函数时传递不可变与不可变对象,如下所示。
1 def test1(alist):
2 alist.append(5)
3 print(alist)
4 def test2(astr):
5 astr += '.com'
6 print(astr)
7 list1 = [2, 3, 4, 5]
8 str1 = 'sunyuyu'
9 test1(list1) # 可变对象
10 test2(str1) # 不可变对象
11 print(list1, str1)
运行结果如下图所示。

在上例中,第9行调用test1()函数,实参为可变对象,第10行调用test2()函数,实参为不可变对象。从程序运行结果可发现,可变对象可以被修改,但不可变对象不能被修改。
网友评论