
今天,咱就来聊聊 Python 函数参数中的两个 “魔法参数”——*args 和 **kwargs,它们能让你的函数变得超级灵活,轻松应对各种复杂情况。不过对于新接触Python的同学来说是一个不好理解的概念,Up第一次接触也觉得过于灵活而不好理解。今天,Up尝试用通俗易懂的语言来说清楚。
在深入了解 * args 和 **kwargs 之前,咱们得先熟悉一下 Python 函数参数中的两个 “常规军”—— 位置参数和关键字参数,它们可是函数传参的基础。
位置参数,顾名思义,就是在调用函数时,按照参数的顺序依次传递给函数的参数,实参的位置和形参的位置要一一对应,就像排队领东西,先来的先领,顺序不能乱。比如说,咱们定义一个计算两数之和的函数:
def add_numbers(a, b): return a + b
这里的 a 和 b 就是位置参数,当我们调用这个函数时,就得按照顺序传入两个数:
result = add_numbers(3, 5) print(result)
在这个例子中, 3 会被赋值给 a, 5 会被赋值给 b,函数返回它们的和 8。
而关键字参数呢,就灵活多了。它是指在调用函数时,通过指定参数名来为参数赋值,这样就不用拘泥于参数的位置顺序,让代码更加清晰易读。还是用刚才的加法函数举例,我们可以这样调用:
result = add_numbers(a=3, b=5)
甚至还可以交换顺序:
result = add_numbers(b=5, a=3)
不管顺序如何,只要参数名写对,就能准确地把值赋给对应的形参,是不是很方便?这在函数参数较多的时候特别有用,能让你一眼就看明白每个参数的含义。
另外,位置参数和关键字参数还能混合使用,不过要记住一条规则:位置参数必须在关键字参数之前。比如:
def greet(name, message): print(f"{message}, {name}!") greet("小明", message="你好")
这样写没问题,但要是写成 greet(message=“你好”, “小明”),Python 就会报错,因为违反了位置参数在前的原则。
*args 就像是一个 “参数收集器”,它能够把函数调用时多余的位置参数一股脑儿地收集起来,然后打包成一个元组(tuple)。这里要注意哦,名字不一定非得是args,写成numbers、values 之类的都没问题,关键是那个星号,它就像是一个 “魔法标记”,告诉 Python:“嘿,我要收集多余的位置参数啦!”
咱们来看个例子,假如你要写一个函数,计算任意多个数字的总和,你不确定用户会输入几个数字,这时候 * args 就能大显身手了:
def sum_numbers(*args): total = 0 for number in args: total += number return total
在这个函数里,*args 就像一个口袋,不管你传入多少个位置参数,它都能接住,然后把这些参数变成一个元组。比如,咱们这样调用这个函数:
result = sum_numbers(1, 2, 3, 4, 5) print(result)
这里传入的 1、2、3、4、5 就会被 * args 收集起来,变成元组 (1, 2, 3, 4, 5),然后在函数内部,通过循环遍历这个元组,把每个数字相加,最终得到总和 15。
讲完了*args,咱们再来看看另一位主角 ——**kwargs。它同样有个神奇的 “魔法标记”—— 两个星号**,有了它,函数就能把调用时传入的任意数量的关键字参数统统收集起来,整理成一个字典(dict)。和 * args 一样,名字不固定,写成 **params、**options 之类的都行,关键是那两个星号。
咱们来看个例子,假如你要写一个函数,用来展示一个人的详细信息,你不知道用户会提供哪些具体信息,这时候 **kwargs 就能派上用场啦:
def show_person_info(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}")
在这个函数里,**kwargs 就像一个万能的信息收纳盒,不管你传入多少个关键字参数,它都能接住,然后把这些参数变成一个字典。比如,咱们这样调用这个函数:
show_person_info(name="小明", age=20, city="北京")
这里传入的 name=“小明”、age=20、city=“北京” 就会被 **kwargs 收集起来,变成字典 {“name”: “小明”, “age”: 20, “city”: “北京”},然后在函数内部,通过遍历这个字典,把每个键值对都打印出来,展示出这个人的详细信息。
从函数定义的角度来看,**kwargs 也必须放在参数列表的最后面,这是为了让 Python 解释器能正确地识别参数。要是你把它放在前面,后面的参数就可能会被误认成关键字参数,导致程序出错。
了解了 * args 和 **kwargs 各自的特点,接下来咱们看看怎么把它们结合起来使用.
在实际编程中,有很多场景需要同时处理位置参数和关键字参数,而且数量还不确定。比如说,你要写一个函数来记录日志信息,日志可能包含一些固定的格式信息(类似关键字参数),还可能有一些额外的描述信息(类似位置参数),这时候 * args 和 **kwargs 就能完美配合。
咱们来看个例子:
def log_message(message_type, *args, **kwargs): print(f"[{message_type}]") for arg in args: print(arg) for key, value in kwargs.items(): print(f"{key}: {value}")
在这个 log_message 函数中, message_type 是一个固定的位置参数,用来指定日志的类型,比如 “ERROR”、“INFO” 之类的。而 *args 用来接收一些额外的描述信息,**kwargs 则用来接收一些带有特定名称的详细信息,像日志发生的时间、代码行数等。
咱们这样调用这个函数:
log_message("INFO", "程序启动成功", time="2023-09-15 10:00:00", line_number=100)
这里,“程序启动成功” 会被args 收集,变成元组 (“程序启动成功”,),而 time=“2023-09-15 10:00:00” 和 line_number=100 会被**kwargs 收集,变成字典 {“time”: “2023-09-15 10:00:00”, “line_number”: 100}。函数内部先打印日志类型 “INFO”,接着遍历*args 打印额外描述,再遍历 **kwargs 打印详细信息,输出就会像这样:
[INFO] 程序启动成功 time: 2023-09-15 10:00:00 line_number: 100
聊完了 * args 和 **kwargs 的基本用法,咱再来看看它们在装饰器里如何使用!
对于装饰器不太熟悉的小伙伴,可以看一下Up上期的文章哦!
那*args 和 **kwargs 在装饰器里起什么作用呢?想象一下,如果被装饰的函数可能接收不定数量的参数,就像咱们之前讲的*args 和**kwargs 的用法,这时候装饰器里的内部函数就得用 *args 和**kwargs 来接收这些参数,然后原封不动地传给原函数,否则参数就传递不进去,会导致报错。
咱们来看个例子,假设你要写一个装饰器,用来记录函数的执行时间,不管这个函数接收几个参数,都能正常工作:
import time def timeit(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"{func.__name__} 函数执行时间: {end_time - start_time} 秒") return result return wrapper @timeit def add_numbers(*args): return sum(args) @timeit def show_info(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}")
在这个例子中, timeit 是装饰器函数,它的内部函数 wrapper 使用 * args 和 **kwargs 接收任意数量的参数,然后把这些参数传给原函数 func,不管是 add_numbers 函数接收不定数量的位置参数,还是 show_info 函数接收不定数量的关键字参数,都能被 wrapper 函数正确接收并传递,同时还能记录下函数的执行时间。比如,咱们调用 add_numbers(1, 2, 3, 4, 5),会先记录开始时间,执行 add_numbers 函数计算总和,再记录结束时间,打印出函数执行时间,最后返回总和;调用 show_info(name=“小明”, age=20) 也是类似,先记录时间,打印信息,再返回 None(因为 show_info 函数没有返回值)。
要是装饰器里的内部函数不使用 * args 和 *kwargs,而是写死了固定的参数,那这个装饰器就只能用于特定参数数量和类型的函数,灵活性就大打折扣了。比如说,你把 wrapper 函数写成 def wrapper(a, b),那它就只能装饰接收两个位置参数的函数,要是用来装饰 add_numbers(args) 这种不定参数的函数,就会报错,提示参数数量不匹配。
所以说,args 和 **kwargs 在装饰器里就像是两座 “桥梁”,让装饰器能够无缝对接各种不同参数的函数,极大地拓展了装饰器的应用范围,让你的代码复用性更强,不管是简单的函数增强,还是复杂的框架开发,都离不开它们的身影,掌握了在装饰器中使用args 和 **kwargs 的技巧,你就能在 Python 编程的世界里更加游刃有余啦!
到此这篇关于Python魔法参数args和kwargs的文章就介绍到这了,更多相关Python魔法参数args和kwargs内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!