1)可变位置参数
在Python中,函数在定义时可以拥有任意数量的参数,这种参数称为可变参数。可以通过定义可变参数,来接收调用函数时多余的参数。可变参数又分为可变位置参数和可变关键字参数,它们的区别如下:
①可变位置参数用来接收调用函数时多余的位置参数;在函数体内,可变位置参数是一个元组。
②可变关键字参数用来接收调用函数时多余的关键字参数;在函数体内,可变关键字参数是一个字典。
可变位置参数是在普通的参数前面加一个星号“*”,一般命名为args(arguments的缩写),但实际上它可以用任意合法的名称:
- >>> def f(*args): # *args是可变位置参数
- ... print(args) # 打印args
- ... print(type(args)) # 打印args的类型
- ... for i in args: # 迭代元组
- ... print(i)
- ...
- >>> f('Python', 42, 3.14)
- ('Python', 42, 3.14)
- <class 'tuple'>
- Python
- 42
- 3.14
由运行结果可知,可变位置参数在函数体内是一个元组。另外,函数体内的args不需要加星号。
在定义函数时,如果不确定所需要的参数个数,那么可以使用可变参数。假设要写一个算术加法运算的程序,不使用可变参数时,只能将确定个数的数字相加:
- >>> def add_numbers(a, b, c): # 这个函数只能让三个数字相加
- ... print(a + b + c)
- ...
- >>> add_numbers(1, 2, 3)
- 6
如果使用可变参数,那么可以实现让任意个数的数字相加:
- >>> def add_numbers(*numbers): # 将可变位置参数命名为numbers
- ... sum = 0
- ... for i in numbers: # 由于numbers是元组,因此,可以使用for循环迭代
- ... sum += i
- ... print(sum)
- ...
- >>> add_numbers(1, 2, 3, 4, 5, 6)
- 21
- >>> add_numbers(42, 19, 25)
- 86
- >>> add_numbers() # 可变位置参数也可以传递0个参数
- 0
可变位置参数可以与普通的参数混用。假设要打印一份水果店的公告,其中第一个参数是普通的参数,代表水果店的名字,第二个参数是可变位置参数,用来接收除了水果店名字之外的其他位置参数:
- >>> def fruit_shop(shop_name, *fruits):
- ... print('{0}水果店开业啦!'.format(shop_name))
- ... print('在售的水果有:')
- ... for fruit in fruits:
- ... print(fruit)
- ...
- >>> fruit_shop('小明', '苹果', '香蕉', '西瓜')
- 小明水果店开业啦!
- 在售的水果有:
- 苹果
- 香蕉
- 西瓜
函数调用时,'小明'被shop_name接收,剩余的值都被*fruits接收,并存储在fruits元组中。
2)可变关键字参数
可变关键字参数是在普通的参数前面加两个星号“**”,一般命名为kwargs(keyword arguments的缩写),但实际上它可以用任意合法的名称:
- >>> def f(**kwargs): # **kwargs是可变关键字参数
- ... print(kwargs)
- ... print(type(kwargs)) # 打印kwargs的类型
- ... for k, w in kwargs.items(): # 迭代字典
- ... print('{0}--{1}'.format(k, w))
- ...
- >>> f(name='Ming', age=19) # 使用关键字参数才能将值存储到kwargs中
- {'name': 'Ming', 'age': 19}
- <class 'dict'>
- name--Ming
- age--19
- >>> f() # 可变关键字参数也可以传递0个参数
- {}
可变关键字参数可以与普通的参数混用。假设在前面的“水果店”程序中,不仅打印水果的名称,还打印水果的个数:
- >>> def fruit_shop_v2(shop_name, **fruits):
- ... print('{0}水果店开业啦!'.format(shop_name))
- ... print('在售的水果有:')
- ... for fruit, count in fruits.items(): # 迭代字典
- ... print('{0}{1}个'.format(fruit, count))
- ...
- >>> fruit_shop_v2(shop_name='小明', 苹果=10, 香蕉=3, 橘子=201)
- 小明水果店开业啦!
- 在售的水果有:
- 苹果10个
- 香蕉3个
- 橘子201个
下面是一个更复杂的“水果店”程序,四个参数中,shop_name代表商店名称,open_time代表开业时间,*fruits代表水果种类,**other_info代表水果店还想打印的额外信息:
- >>> def fruit_shop_v3(shop_name, open_time='10月1日', *fruits, **other_info):
- ... print('{0}水果店将在{1}开业!'.format(shop_name, open_time))
- ... if fruits:
- ... print('在售的水果有:')
- ... for fruit in fruits:
- ... print(fruit)
- ... if other_info:
- ... print('以下是额外信息:')
- ... for item, info in other_info.items():
- ... print('{0}:{1}'.format(item, info))
- ...
- >>> fruit_shop_v3('小明') # shop_name既没默认值,又不是可变参数,故不能缺省
- 小明水果店将在10月1日开业!
- >>> fruit_shop_v3('小明', '1月1日') # 提供shop_name和open_time
- 小明水果店将在1月1日开业!
- >>> fruit_shop_v3(open_time='1月1日') # 如果不指定shop_name的值,会报错
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- TypeError: fruit_shop_v3() missing 1 required positional argument: 'shop_name'
- >>> fruit_shop_v3('小明', '苹果', '香蕉', '橘子')
- 小明水果店将在苹果开业!
- 在售的水果有:
- 香蕉
- 橘子
- >>> fruit_shop_v3('小明', '10月1日', '苹果', '香蕉', '橘子')
- 小明水果店将在10月1日开业!
- 在售的水果有:
- 苹果
- 香蕉
- 橘子
- >>>
- >>> fruit_shop_v3('小明', '10月1日', '苹果', '香蕉', 地址='北京市', 开店折扣='八折') # 多余参数全部被**other_info接收
- 小明水果店将在10月1日开业!
- 在售的水果有:
- 苹果
- 香蕉
- 以下是额外信息:
- 地址:北京市
- 开店折扣:八折