Python 函数定义时支持可变数量的参数。
一、默认值参数
在 Python 中给函数的参数指定默认值是一种十分常见的使用方式,这样在调用函数时,可以使用比定义时更少的参数。
示例代码
-
def chat_request(response, retries=4, reminder='Please try again!'):
-
while True:
-
response = input(response)
-
if response in ('y', 'yes'):
-
return True
-
if response in ('n', 'no'):
-
return False
-
retries = retries - 1
-
if retries < 0:
-
raise ValueError('invalid user response')
-
print(reminder)
示例代码中定义的函数chat_request
可以使用以下三种调用方式:
只给出必选实参response
chat_request('hello world!')
给出一个可选实参retries
chat_request('please say no or yes', 2)
给出所有实参response, retries, reminder
chat_request('please input your mind', 2, 'Dear Baby, but only yes or no!')
默认值在 定义
作用域里的函数定义中求值,为理解这句话的含义,请看如下示例。
Input:
-
name = 'tony'
-
def get_name(arg=name):
-
print(arg)
-
name = 'lily'
-
get_name()
Output:
tony
PS: 默认值只计算一次,默认值为列表、字典或类实例等可变对象时,会产生与该规则不同的结果。
例如,下面的get_num
函数会累积后续调用时传递的参数,可以发现输出结果与预期不一致。
Input:
-
def get_num(num, list1=[]):
-
list1.append(num)
-
return list1
-
print(get_num(100))
-
print(get_num(200))
-
print(get_num(300))
Output:
-
[100]
-
[100, 200]
-
[100, 200, 300]
PS: 如果不想在后续调用之间共享默认值时,可采取以下方式改写get_num
函数
Input:
-
def get_num(num, list1=None):
-
if list1 is None:
-
list1 = []
-
list1.append(num)
-
return list1
-
-
print(get_num(100))
-
print(get_num(200))
-
print(get_num(300))
Output:
-
[100]
-
[200]
-
[300]
二、关键字参数
在 Python 中也可以使用kwarg=value
形式的关键字参数来调用函数。
示例代码
-
def animal(name, state='active', action='fly', type='land'):
-
print("This animal wouldn't", action, end=' ')
-
print("if you reminder", name, "you are great.")
-
print("-- general animal, the", type)
-
print("-- They're", state, "!")
代码参数说明
animal
函数接受一个必选参数(name)和三个可选参数(state, action 和 type)。
该函数有以下几种调用方式。
-
animal('jingmao') # 1 positional argument
-
animal(name='keji') # 1 keyword argument
-
animal(name='chaiquan', action='running') # 2 keyword arguments
-
animal(action='sleep', name='pig') # 2 keyword arguments
-
animal('cat', 'smile', 'jump') # 3 positional arguments
-
animal('bird', state='inactive') # 1 positional, 1 keyword
以下都是无效的调用方式。
-
animal() # required argument missing
-
animal(name='rabbit', 'dead') # non-keyword argument after a keyword argument
-
animal('fox', name='bird') # duplicate value for the same argument
-
animal(profile='warning') # unknown keyword argument
函数调用时,关键字参数必须跟在位置参数后面。所有传递的关键字参数都必须匹配一个函数接受的参数。
例如,profile 不是函数 animal 的有效参数,关键字参数的顺序并不重要。这也包括必选参数
PS: 不能对同一个参数多次赋值。
下面的举例就是一个反例
-
def get_name(name):
-
print(name)
-
get_name('dog', name='cat')
-
Traceback (most recent call last):
-
File "<stdin>", line 1, in <module>
-
TypeError: get_name() got multiple values for argument 'name'
在 Python 中形参还可以是 **name
形式,指接收一个字典(kwarg=value),该字典包含与函数中已定义形参对应之外的所有关键字参数。
**name
形参可以与 *name
(指接收一个元组,该元组包含形参列表之外的位置参数)形参组合使用,请注意:*name 必须在 **name 前面
示例代码
Input:
-
def animalShop(animal_name, *arguments, **keywords):
-
print("-- Do you have any", animal_name, "?")
-
print("-- I'm sorry, we're all out of", animal_name)
-
for argument in arguments:
-
print(argument)
-
print("*" * 40)
-
for keyword in keywords:
-
print(keyword, ":", keywords[keyword])
animalShop
函数可以使用如下方式调用
-
animalShop("dog", "It's very Cute, sir.",
-
"It's really very, VERY Smart, sir.",
-
shopkeeper="tony",
-
client="Online Shop",
-
market="Chat Connect")
Output:
-
-- Do you have any dog ?
-
-- I'm sorry, we're all out of dog
-
It's very Cute, sir.
-
It's really very, VERY Smart, sir.
-
****************************************
-
shopkeeper : tony
-
client : Online Shop
-
market : Chat Connect
PS: 注意,关键字参数在输出结果中的顺序与调用函数时的顺序一致。
三、特殊参数
在 Python 函数中,默认情况下,参数可以按位置
或显式关键字
传递。
但为了让代码易读、高效,最好限制参数的传递方式,这样,开发者只需查看函数定义,即可确定参数项是仅按位置
、按位置或关键字
,还是仅按关键字
传递。
函数定义如下:
-
def function(position_arg1, position_arg2, /, position_or_keyword, *, kwd1, kwd2):
-
pass
在function
函数定义中:
-
position_arg1
和position_arg2
仅仅只是位置参数 -
position_or_keyword
可以是位置参数也可以是关键字参数 -
kwd1
和kwd2
仅仅只是关键字参数
PS: /
和*
是可选的,这些符号表明形参如何把参数值传递给函数:位置、位置或关键字、关键字。关键字形参也叫作命名形参。
3.1 位置或关键字参数
函数定义中未使用 / 和 * 时,参数可以按位置或关键字传递给函数。
3.2 仅位置参数
细节补充一下,特定形参可以标记为 仅限位置
。
-
仅限位置
时,形参的顺序很重要,且这些形参不能用关键字传递。仅限位置形参应放在/
(正斜杠)前。 -
/
用于在逻辑上分割仅限位置形参与其它形参。如果函数定义中没有/
,则表示没有仅限位置形参。 -
/
后可以是 位置或关键字 或 仅限关键字 形参。
3.3 仅限关键字参数
细节补充一下,把形参标记为 仅限关键字
,表明必须以关键字参数形式传递该形参,应在参数列表中第一个 仅限关键字 形参前添加 *
。
示例代码
如下函数定义示例,注意 /
和 *
标记。
-
def standard_arg(arg):
-
print(arg)
-
def pos_only_arg(arg, /):
-
print(arg)
-
def kwd_only_arg(*, arg):
-
print(arg)
-
def union_example(pos_only, /, standard, *, kwd_only):
-
print(pos_only, standard, kwd_only)
第一个函数定义 standard_arg 是最常见的形式,对调用方式没有任何限制,可以按位置也可以按关键字传递参数
-
# 按位置传递参数
-
standard_arg(200)
-
200
-
# 按关键字传递参数
-
standard_arg(arg=200)
-
200
第二个函数 pos_only_arg 的函数定义中有 /,仅限使用位置形参
-
# 按位置传递参数正常,无报错
-
pos_only_arg(100)
-
100
-
# 按关键字传递参数异常,会抛异常
-
pos_only_arg(arg=100)
-
Traceback (most recent call last):
-
File "<stdin>", line 1, in <module>
-
TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'
第三个函数 kwd_only_args 的函数定义通过 *
表明仅限关键字参数
-
# 按位置传递参数异常,会抛异常
-
kwd_only_arg(300)
-
Traceback (most recent call last):
-
File "<stdin>", line 1, in <module>
-
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
-
# 按关键字传递参数正常,无报错
-
kwd_only_arg(arg=300)
-
3
最后一个函数 union_example 在同一个函数定义中,使用了全部三种调用方式
-
# 第3个参数仅为关键字参数,这里使用位置参数传参,会报错
-
union_example(100, 200, 300)
-
Traceback (most recent call last):
-
File "<stdin>", line 1, in <module>
-
TypeError: union_example() takes 2 positional arguments but 3 were given
-
# 第2个参数使用位置参数传参,无报错
-
union_example(100, 200, kwd_only=300)
-
输出:100 200 300
-
# 第2个参数使用关键字参数传参,无报错
-
union_example(100, standard=200, kwd_only=300)
-
输出:100 200 300
-
# 第1个参数仅为位置参数,这里使用关键字参数传参,会报错
-
union_example(pos_only=100, standard=200, kwd_only=300)
-
Traceback (most recent call last):
-
File "<stdin>", line 1, in <module>
-
TypeError: union_example() got some positional-only arguments passed as keyword arguments: 'pos_only'
位置参数与关键字参数key名称冲突
在 key_error 函数定义中,kwargs 把 name 当作键,可能与位置参数 name 产生潜在冲突
Input:
-
def key_error(name, **kwargs):
-
return 'name' in kwargs
Output:
-
key_error('tony', **{'name': 'lucy'})
-
Traceback (most recent call last):
-
File "<stdin>", line 1, in <module>
-
TypeError: key_error() got multiple values for argument 'name'
冲突解决方法
在位置参数 name 后加上 / (仅限位置参数)就可以了。
此时,函数定义把 name 当作位置参数,'name' 也可以作为关键字参数的键了。
即:仅限位置形参的名称可以在 **kwargs 中使用,不会产生冲突。
-
def key_error(name, **kwargs):
-
return 'name' in kwargs
-
key_error('tony', **{'name': 'lucy'})
-
True
四、任意实参列表
在 Python 函数调用过程中使用任意数量的实参是不常见的,通常这些实参包含在元组中。
在可变数量的实参之前,可能有若干个普通参数,如下示例代码。
-
def person(p_file, separator, *args):
-
p_file.write(separator.join(args))
*args
形参后的任何形式参数只能是仅限关键字参数,即只能用作关键字参数,不能用作位置参数,如下示例代码。
-
def test_concat(*args, sep="/"):
-
return sep.join(args)
-
test_concat("name", "sex", "age")
-
'name/sex/age'
-
test_concat("name", "sex", "age", sep=".")
-
'name.sex.age'
五、解包实参列表
在 Python 中函数调用需要独立的位置参数,如果是可变数量的位置参数,它的实参在列表或元组里时,要执行相反的操作。
例如,常用的内置 range()
函数要求传递独立的 start 和 stop 实参。
如果这些参数不是独立的,则要在调用函数时,用 *
操作符把实参从列表或元组解包出来。
示例代码
-
list(range(1, 4)) # normal call with separate arguments
-
输出:[1, 2, 3]
-
moreNumber_args = [1, 4]
-
list(range(*moreNumber_args)) # call with arguments unpacked from a list
-
输出:[1, 2, 3]
同理,字典可以用 **
操作符传递关键字参数
-
def animal(name, state='active', action='fly'):
-
print("This animal wouldn't", action, end=' ')
-
print("if you reminder", name, "you are great.", end=' ')
-
print("-- They're", state, "!")
-
-
d = {"name": "dog", "state": "active", "action": "run"}
-
animal(**d)
-
输出:This animal wouldn't run if you reminder dog you are great. -- They're active !
行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!