Python *args 用法笔记

整理自《Effective Python 编写高质量 Python 代码的 59 个有效方法》第 18 条。

1. 定义、用法

在 def 语句中使用 *args,即可令函数接受数量可变的位置参数。

比如确定一个函数接收 message 信息参数和 values 值参数,但不确定 values 有几个值,解决方法可以把 values 定义成列表,有数据就塞入列表,无数据就空列表,得到如下函数代码:

def log(message,values):
    if not values:
        print(message)
    else:
        value_str = ", ".join(str(x) for x in values)
        print(f"{message}: {value_str}")


log("My numbers are",[1,2])
log("Hi",[])

倘若不想使用列表,就想直接将 values 值一个个作为参数传入函数,可以在最后的位置参数前加 * 表示可以跟随任意数量的位置参数:

def log(message,*values):
    if not values:
        print(message)
    else:
        value_str = ", ".join(str(x) for x in values)
        print(f"{message}: {value_str}")


log("My numbers are",1,2)
log("Hi")

此时就不需要将 values 做成列表来传入了,有数据就传,没数据就空着。

2. * 操作符分解序列

此外,我采用了刚 *values 的位置参数标注法,但我现在拿到的是个列表,想把列表中的元素作为参数传上去,这个要怎么处理,总不能再重写个函数吧?这里就要用到在列表前加星号了,看代码,函数定义不变,但调用函数传参数时给列表前加个星号:

def log(message,*values):
    if not values:
        print(message)
    else:
        value_str = ", ".join(str(x) for x in values)
        print(f"{message}: {value_str}")


log("My numbers are",1,2)
log("Hi")
# 看这里
log("My numbers are",*[1,2,3,4,5])

这种 *[1,2,3,4,5] 的形式就是对列表拆解,将其中元素拿出来当参数使用

3. 可能耗尽内存并崩溃

变长参数传给函数时,总是要先转化成元组。那么当我们把刚刚 *[1,2,3,4,5] 要拆解的列表换成个生成器,把它当参数传入函数时,Python 就必须把该生成器完整迭代一轮将所有生成的值放入元组,这就有可能消耗大量内存并导致程序崩溃。

使用 *args 来表示任意参数主要是为了简化程序员编码工作,并使代码更加易读。

4. 可能产生难以排查的 bug

对于已经使用 *args 位置参数的函数,如果以后要给函数添加新的位置参数,那就必须修改原来调用该函数的旧代码。若只在参数列表前添加新的位置参数,而不更新现有的调用代码,则可能会产生难以调试的错误。

例如我们在刚刚代码基础上添加个 sequence 参数:

def log(sequence,message,*values):
    if not values:
        print(message)
    else:
        value_str = ", ".join(str(x) for x in values)
        print(f"{sequence}:{message}: {value_str}")


# 正常
log(1,"My numbers are",1,2)
# 错误,但不报错
log("My numbers are",7,33)

添加了新参数、但仍按之前某种方式调用时,参数混乱配置,但没抛出异常仍是正常运行。

为了彻底避免此类情况,我们应该使用只能以关键字形式指定的参数(keyword-only argument) 来扩展这种接受 *args 的函数。

<think>好的,用户现在问的是“args是什么”,需要我详细解释一下。首先,我要确定用户指的是Python中的*args,因为“args”本身可能有很多含义,但在编程尤其是Python的上下文中,最常见的是可变位置参数。 接下来,我需要回顾之前的对话历史。用户之前询问了try和except,现在转向函数参数,可能是在学习Python的基础知识,逐步深入。这时候可能需要用简单明了的语言,避免术语过多,但也要确保准确性。 用户可能的需求是理解函数定义中*args的作用,或者遇到了相关代码示例,需要解释。他们可能刚开始学习函数,对于可变参数的概念不太清楚,所以需要从基础讲起,比如函数定义、参数传递,然后引入*args的作用和用法。 我需要考虑是否需要区分位置参数和关键字参数,但用户的问题只提到了args,所以可能先专注于位置参数。不过,可能需要简要提到**kwargs作为扩展,但主要解释*args。 用户可能的深层需求是理解如何编写更灵活的函数,处理不同数量的参数,比如写一个求和函数,可以接受任意数量的参数。这时候举例会很有帮助,比如sum函数或打印多个值的例子。 同时,要注意结构清晰,分点解释,比如基本概念、语法、使用场景、注意事项、与普通参数的区别等。可能还需要指出常见错误,比如在函数调用时忘记加星号,或者混合使用位置参数和*args时的顺序问题。 最后,需要确保回答符合之前的系统级指令,使用正确的中文,数学表达式用$...$格式,如果有代码示例的话要正确标记,但用户这个问题可能不需要数学公式,但需要代码块。同时保持回答结构清晰,逐步引导用户理解。</think>在 Python 中,**`*args`** 是一个用于函数定义的语法,表示**接受任意数量的位置参数**(Positional Arguments)。以下是详细解释: --- ### **1. 基本概念** - **作用**:允许函数接收比定义时更多的参数,适用于参数数量不确定的场景。 - **名称惯例**:`args` 是约定俗成的变量名(可替换为其他名称,但需保留 `*` 符号)。 - **底层原理**:`*` 符号会将所有传入的位置参数打包成一个**元组**(tuple)。 --- ### **2. 语法示例** ```python def my_function(*args): print("接收的参数:", args) my_function(1, 2, 3, "hello") ``` 输出: ``` 接收的参数: (1, 2, 3, 'hello') ``` --- ### **3. 典型使用场景** #### **场景1:处理不确定数量的参数** 例如,实现一个求和函数,可接受任意数量的数字: ```python def sum_all(*args): total = 0 for num in args: total += num return total print(sum_all(1, 2, 3)) # 输出:6 print(sum_all(10, 20)) # 输出:30 ``` #### **场景2:组合普通参数与 `*args`** 普通参数必须定义在 `*args` 之前: ```python def greet(name, *messages): print(f"你好,{name}!") for msg in messages: print(msg) greet("Alice", "今天天气不错", "欢迎学习Python") ``` 输出: ``` 你好,Alice! 今天天气不错 欢迎学习Python ``` --- ### **4. 注意事项** 1. **顺序限制**:`*args` 必须定义在**普通位置参数之后**,但**关键字参数之前**。 ```python def valid(a, b, *args, c=0): # 正确 pass def invalid(*args, a, b): # 错误(普通参数不能在 *args 后) pass ``` 2. **与 `**kwargs` 的区别**: - `*args` 接收**位置参数**,打包为元组。 - `**kwargs` 接收**关键字参数**,打包为字典。 3. **函数调用时的解包**: 在调用函数时,`*` 也可用于解包序列: ```python numbers = [1, 2, 3] sum_all(*numbers) # 等效于 sum_all(1, 2, 3) ``` --- ### **5. 常见问题** #### **Q:为什么不用列表直接传参?** 使用 `*args` 的优势在于**灵活性**,调用时可直接写参数,无需提前构造列表: ```python # 直接传参更直观 sum_all(1, 2, 3) # 对比需要手动解包列表 numbers = [1, 2, 3] sum_all(*numbers) ``` #### **Q:能否修改 `*args` 的内容?** 可以,但需先将其转换为可变类型(如列表): ```python def modify_args(*args): args_list = list(args) # 转为列表 args_list[0] = 100 print(args_list) modify_args(1, 2, 3) # 输出:[100, 2, 3] ``` --- ### **6. 总结** - **核心用途**:处理不确定数量的位置参数。 - **底层结构**:参数被打包为元组。 - **扩展应用**:常与 `**kwargs` 配合使用,构建高度灵活的函数接口。 通过 `*args`,Python 函数可以更优雅地应对多样化的参数需求,是编写通用工具函数的重要技术。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值