[赞] 点赞、收藏、加关注,下次找我不迷路摘要:写函数时参数总是写死,遇到参数数量变化就抓瞎?比如想写个求和函数,既能算两个数相加,又能算十个八个数相加;或者写个用户信息函数,有的人需要传年龄,有的人需要传地址,参数老是不够用...... 别慌!Python 的动态参数就是来解决这些的!
写函数时参数总是写死,遇到参数数量变化就抓瞎?比如想写个求和函数,既能算两个数相加,又能算十个八个数相加;或者写个用户信息函数,有的人需要传年龄,有的人需要传地址,参数老是不够用...... 别慌!Python 的动态参数就是来解决这些的!
一、啥是动态参数?先搞懂这两个符号 (一)*args:专治「位置参数太多」
先看个简单例子:假设我们要写一个函数,能计算任意个数的和。如果按普通方法写,参数数量固定,比如:
那如果要算 3 个数相加,就得再写个add(a, b, c),算 10 个数就得写 10 个参数,这显然太麻烦了!这时候*args就派上用场了,它就像一个能装任意多个位置参数的「魔法口袋」,把多个参数打包成一个元组。
用法演示:
def add(*args): total = 0 for num in args: total += num return totalprint(add(1, 2)) # 3print(add(1, 2, 3, 4)) # 10print(add(1, 2, 3, 4, 5, 6, 7)) # 28这里的*args其实就是arguments的缩写,代表任意数量的位置参数。调用函数时,不管传多少个参数,都会被args这个元组装起来,然后我们就可以用循环来处理啦。
(二)**kwargs:搞定「关键字参数多变」
再来看另一个场景:比如我们要写一个打印用户信息的函数,不同用户可能有不同的属性,比如有的人需要传name和age,有的人需要传name、address和phone。这时候**kwargs就闪亮登场了,它是一个能装任意多个关键字参数的「百宝盒」,把参数打包成一个字典。
用法演示:
def print_info(**kwargs): for key, value in kwargs.items: print(f"{key}: {value}")print_info(name="小明", age=18)# 输出:# name: 小明# age: 18print_info(name="小红", address="北京", phone=13800001111)# 输出:# name: 小红# address: 北京# phone: 13800001111**kwargs是keyword arguments的缩写,调用函数时传入的关键字参数(比如name="小明")会被收集到kwargs这个字典里,键是参数名,值是对应的值。我们可以用字典的items方法来遍历输出。
(三)一句话总结:单星打包位置参数,双星打包关键字参数
为了方便记忆,咱们来个简单的口诀:
「单星 * args,位置参数全收下;双星**kwargs,关键字参数装回家」
二、*args 和 **kwargs 的核心区别:一张表让你秒懂
为了让大家更清楚两者的区别,咱们用表格来对比一下:
特性
*args
**kwargs
语法
单个星号 + 参数名(*args)
两个星号 + 参数名(**kwargs)
传递方式
接收位置参数(如:1, 2, 3)
接收关键字参数(如:a=1, b=2)
接收类型
元组(tuple)
字典(dict)
应用场景
参数数量不定的位置参数
参数名称不定的关键字参数
参数顺序
按位置传递,顺序重要
按关键字传递,顺序不重要
举个生活中的例子帮助理解:*args 就像去超市购物,把选好的商品(位置参数)一股脑扔进购物车(元组),结账时按放进的顺序处理;kwargs 就像点外卖,把想要的菜品(关键字参数,比如「宫保鸡丁 = 1 份」)写在订单里(字典),商家按订单名称准备,不管你先写哪个后写哪个。
三、动态参数原来还能这么用! (一)混合使用:固定参数 + 动态参数,灵活又可控
有时候我们的函数既有固定参数,又需要动态参数,这时候只要注意顺序就行:** 固定参数在前,*args 在中间,kwargs 在最后。比如写一个函数,需要先传一个必选的title,然后可以传任意多个位置参数(比如文章的关键词),最后可以传任意多个关键字参数(比如作者信息):
def write_article(title, *keywords, **author_info): print(f"文章标题:{title}") print(f"关键词:{keywords}") print(f"作者信息:{author_info}")write_article("Python动态参数", "Python", "函数", "参数", name="小李", experience=3)# 输出:# 文章标题:Python动态参数# 关键词:('Python', '函数', '参数')# 作者信息:{'name': '小李', 'experience': 3}这里的顺序一定不能搞错哦,如果把 **kwargs 放在 * args 前面,就会报错,因为 Python 会把后面的位置参数当成关键字参数,这就乱套啦~
(二)解包操作:把打包的参数再拆开用
前面咱们说的是用 * args 和 **kwargs 来打包参数,其实它们还能反过来「解包」,把已有的列表、元组、字典拆成单个参数传给函数。
1. 解包列表 / 元组:用单个星号 *
比如有一个列表nums = [1, 2, 3, 4],想传给前面写的add函数:
nums = [1, 2, 3, 4]print(add(*nums)) # 10,相当于调用add(1, 2, 3, 4)这里的*nums就是把列表解包成单个的位置参数,传给add函数里的 * args。
比如有一个字典info = {"name": "小张", "age": 20},想传给print_info函数:
info = {"name": "小张", "age": 20}print_info(**info) # 相当于调用print_info(name="小张", age=20)# 输出:# name: 小张# age: 20解包操作的口诀:单星解包序列(列表 / 元组),双星解包字典,打包解包灵活换,函数调用更方便~
(三)动态参数在函数扩展中的妙用:让旧函数兼容新需求
def old_func(a, b): print(f"a={a}, b={b}")现在需求变了,需要增加一个参数c,但又不想破坏原来的调用方式(比如原来有很多地方调用old_func(1, 2))。这时候可以用动态参数来改造函数,让它既能接收旧的参数,又能处理新的参数:
def new_func(a, b, *args, **kwargs): old_func(a, b) # 先处理原来的固定参数 if args: print(f"新增的位置参数:{args}") if kwargs: if 'c' in kwargs: print(f"新增的c参数:{kwargs['c']}") # 其他新增参数处理...# 旧调用方式不变new_func(1, 2) # 输出:a=1, b=2# 新调用方式可以传c参数new_func(1, 2, c=3) # 输出:a=1, b=2,新增的c参数:3这样一来,旧代码不用改,新需求也能满足,动态参数简直就是函数升级的「桥梁」!
四、有些问题别搞错 (一)参数顺序别搞错:固定参数→*args→**kwargs
前面提到过,混合使用时顺序很重要,要是写成def func(**kwargs, *args),直接就会报错啦!记住口诀:「固定参数先站好,单星双星往后靠」,保证不会错~
(二)别把 * args 和 **kwargs 当「万能钥匙」,够用就行
虽然动态参数很强大,但也不能滥用。如果函数明确知道需要几个固定参数,就别用动态参数,不然会让代码可读性变差。比如add(a, b)就比add(*args)更清晰,除非真的需要处理任意数量的参数。
(三)解包时注意数据类型
解包列表 / 元组到args 没问题,但如果把字典解包到args,就会得到字典的键作为位置参数。比如:
def func(*args): print(args)data = {"a": 1, "b": 2}func(*data) # 输出:('a', 'b'),因为*data解包的是字典的键如果想解包字典的值,需要用data.values,或者直接用 **kwargs 来解包字典:
func(**data) # 这会报错,因为func不接收关键字参数,所以要用能接收**kwargs的函数(四)给动态参数取个好名字:别只用 args 和 kwargs虽然*args和**kwargs是约定俗成的名字,但在实际项目中,如果能根据参数含义取更有意义的名字,会让代码更易读。比如处理学生成绩时,可以用*scores,处理用户信息时用**user_info,这样一看就知道里面装的是什么数据。
最后给大家整理个思维导图梳理一下重点
来源:科技站长