Python3中Variable Length Arguments(*args)与*运算符用法咨询
Python
*args可变长参数与*运算符核心逻辑 两种函数定义、传参方式的核心差异与*args优势
两段测试代码输出一致只是测试场景的巧合,二者底层逻辑完全不同:
- 采用
*args形参的写法:*args在函数定义阶段的作用是将调用时传入的所有位置参数自动打包为一个元组,赋值给args变量。这种写法的函数支持接收任意数量的位置参数,传0个、1个、N个参数都不会触发参数数量错误。示例中kitten(*x)的执行逻辑是:先用*把元组x拆成'meow'、'grrr'、'purr'三个独立参数传入函数,进入函数后这三个参数又被*args重新打包为三元素元组,和直接写kitten('meow', 'grrr', 'purr')的执行效果完全一致。 - 采用普通单形参的写法:函数仅接收1个位置参数,调用时传入什么值,形参
args就原封不动保存什么值。示例中直接传入元组x,args拿到的就是这个三元素元组,循环遍历自然能输出每个字符串;但如果尝试写kitten('meow', 'grrr', 'purr')直接传入三个独立参数,会立刻触发参数数量不匹配的报错。
*args的核心价值是降低函数调用成本:调用方不需要提前把多个参数手动打包为列表、元组等可迭代对象,传入参数的数量完全灵活。内置函数print()就是基于*args实现的,因此你可以直接写print(1,2,3,4)传入任意多个值,不需要每次传参都手动把多个值封装成一个序列。
传参场景下*运算符的运行逻辑
在函数调用的参数位置使用*可迭代对象,作用非常明确:把后方的可迭代对象(元组、列表、字符串等)按顺序拆解为一个个独立的位置参数,按顺序传给目标函数,本身没有额外的特殊逻辑。
测试中不同函数的表现差异,完全由函数本身的参数接收规则决定:
- 执行
print(*x)时:元组x被拆解为3个独立的字符串参数,而print()本身支持接收任意多个位置参数,默认会将收到的多个参数用空格拼接后输出,因此能正常打印meow grrr purr,和直接写print('meow', 'grrr', 'purr')效果完全相同。 - 执行
len(*x)时:元组x被拆解为3个独立参数,但len()的定义是仅允许传入1个可迭代对象参数,传入3个参数自然会触发len() takes exactly one argument (3 given)的报错。 - 执行
type(*x)时:元组x被拆解为3个独立参数,第一个参数是字符串'meow';而type()接收多个参数时是用于动态创建类的特殊语法,要求第二个参数必须是元组类型,传入的第二个参数是字符串'grrr',因此会触发类型不匹配的报错。
补充说明:
*运算符在变量赋值、函数定义场景还有打包剩余元素的作用(比如写法a, *rest = [1,2,3]中,rest会拿到剩余元素组成的列表[2,3],函数定义里的*args就是这个打包逻辑),和传参时的解包逻辑是同一运算符的互补用法。
测试代码参考
*args写法示例
def main(): x = ('meow', 'grrr', 'purr') kitten(*x) # 支持直接传任意数量参数,无需提前打包 kitten('hello', 'world') def kitten(*args): if len(args): for s in args: print(s) else: print('Empty') if __name__ == '__main__': main()
普通单形参写法示例
def main(): x = ('meow', 'grrr', 'purr') kitten(x) # 以下直接传多个参数的写法会触发报错 # kitten('hello', 'world') def kitten(args): if len(args): for s in args: print(s) else: print('Empty') if __name__ == '__main__': main()
*运算符测试示例
x = ('meow', 'grrr', 'purr') print(*x) # 正常输出:meow grrr purr # print(len(*x)) # 报错:len仅接收1个参数 # print(type(*x)) # 报错:多参数传参时类型不匹配
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

