超详细,少数人才知道的 Python 函数定义详解
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 !
最后: 下方这份完整的软件测试视频学习教程已经整理上传完成,朋友们如果需要可以自行免费领取 【保证100%免费】
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!
相关文章
- python执行脚本加参数_命令行运行Python脚本时传入参数的三种方式详解以及argparse子命令subparsers()方法
- Python任意参数的数量/预习课python基础
- 超全Python学习路线图+14张思维导图,让python初学者不走弯路
- Python中的海象运算符“:=”使用方法详解
- python中decimal用法详解
- python内置函数bytearray用法详解
- python内置函数布尔值bool用法详解
- python中tldextract用法详解
- python内置函数all()用法详解
- python中sys.exc_info()函数用法详解
- python中enum枚举类用法详解
- python中getattr()函数用法详解
- python中moviepy库的用法详解
- Python内置函数divmod()用法详解
- python中sort()和sorted()排序函数用法详解
- python内置函数map()函数用法详解
- python函数用法详解2(变量的作用域(全局变量、局部变量)、共享全局变量、函数返回值、函数的参数(位置参数、关键字参数、默认参数、不定长参数)、拆包、交换变量值、引用、可变和不可变类型)
- Python面向对象编程(类编程)中self的含义详解(简单明了直击本质的解释)
- python print 函数详解
- Python 的结构体函数 struct pack, unpack 用法详解
- Python基础必掌握的re模块支持的元字符9类使用详解
- Python 基础 之 python 协程知识点整理,并实现一个简单 gevent 的协程并发图片下载的应用