问题

Python函数中*和**的内涵究竟是什么呢?

回答
这问题问得好,确实,Python 里这两个小东西,`` 和 ``,看似简单,但它们的能耐可大了去,尤其是用在函数定义和调用上,更是能让你的代码变得灵活又强大。咱们这就来捋一捋,把它们说透了。

`args`:收集“散弹”传进来的位置参数

想象一下,你写一个函数,本意是想接收几个固定的参数,比如 `def my_func(a, b):`。但有时候,你可能不知道用户会传进来几个参数,或者你压根就想让这个函数变得更“海纳百川”。这时,`args` 就派上用场了。

内涵是什么?

当你在函数定义时,在某个参数前加上一个 ``(通常习惯写成 `args`,这里的 `args` 是 argument 的缩写,你也可以改成别的名字,比如 `params`,但 `args` 是约定俗成,一看就明白),它就像一个“捕手”,会把所有多余的、没有被其他明确参数接收到的位置参数一股脑儿地收集起来。

它收集起来的是什么?

收集起来的,不是单个的参数,而是一个元组(tuple)。没错,就是一个元组,里面装着所有那些“散弹”式传进来的参数。

怎么理解?

我们来看个例子:

```python
def my_sum(numbers):
total = 0
for num in numbers:
total += num
print(f"接收到的参数是:{numbers}")
return total

调用演示
print(my_sum(1, 2, 3))
输出:
接收到的参数是:(1, 2, 3)
6

print(my_sum(10, 20, 30, 40, 50))
输出:
接收到的参数是:(10, 20, 30, 40, 50)
150

print(my_sum())
输出:
接收到的参数是:()
0
```

在这个 `my_sum` 函数里,我们只定义了 `numbers`。当你调用 `my_sum(1, 2, 3)` 时,`1, 2, 3` 这三个值就构成了一个元组 `(1, 2, 3)`,然后赋值给了 `numbers`。函数内部就可以像操作普通元组一样,遍历它求和。

`args` 的位置很重要

`args` 必须放在所有普通位置参数之后。比如:

```python
def example_func(arg1, arg2, rest):
print(f"第一个参数: {arg1}")
print(f"第二个参数: {arg2}")
print(f"剩余参数: {rest}")

example_func('a', 'b', 'c', 'd', 'e')
输出:
第一个参数: a
第二个参数: b
剩余参数: ('c', 'd', 'e')
```

如果 `args` 放在前面,Python 就不知道哪些是给 `args` 的,哪些是给后面的普通参数的,会报错。

应用场景:

处理不确定数量的参数: 就像上面的求和例子,或者一个打印日志的函数,可以接受任意数量的要打印的内容。
函数装饰器: 装饰器经常需要包装被装饰的函数,而不知道被装饰函数具体接收多少个参数,`args` 就能派上用场,将参数原封不动地传递给被装饰的函数。
函数调用时的“解包”: `` 也可以用在函数调用时,把一个可迭代对象(如列表、元组)的元素“解包”成独立的参数传递进去。

```python
my_list = [5, 6, 7]
print(my_sum(my_list)) 等同于 my_sum(5, 6, 7)
输出:
接收到的参数是:(5, 6, 7)
18
```
看到没?这个 `` 在调用时,就把 `my_list` 里面的 `5, 6, 7` 分别“拆开”,变成了 `my_sum(5, 6, 7)`。

`kwargs`:收集“键值对”传进来的关键字参数

紧接着 `args`,咱们来看看 `kwargs`。如果说 `args` 是收集“散弹”,那 `kwargs` 就是专门用来收集“装箱”的“包裹”——那些以“键=值”形式传进来的参数。

内涵是什么?

在函数定义时,你会在某个参数前加上两个星号 ``(通常习惯写成 `kwargs`,这里的 `kwargs` 是 keyword argument 的缩写,同样可以换名字,但 `kwargs` 是惯例)。它的作用是收集所有多余的、没有被其他明确参数接收到的关键字参数。

它收集起来的是什么?

收集起来的,是一个字典(dictionary)。这个字典的键(key)就是用户传递进来的参数名,值(value)就是对应的参数值。

怎么理解?

还是用例子说话:

```python
def display_info(name, details):
print(f"姓名: {name}")
print("额外信息:")
for key, value in details.items():
print(f" {key}: {value}")

调用演示
display_info("张三", age=25, city="北京", job="工程师")
输出:
姓名: 张三
额外信息:
age: 25
city: 北京
job: 工程师

display_info("李四", country="中国")
输出:
姓名: 李四
额外信息:
country: 中国

display_info("王五") 没有额外信息
输出:
姓名: 王五
额外信息:
```

在这个 `display_info` 函数里,`name` 是一个普通的位置参数,而 `details` 就会接收所有额外的关键字参数。当我们调用 `display_info("张三", age=25, city="北京", job="工程师")` 时,`"张三"` 被赋给了 `name`,而 `age=25, city="北京", job="工程师"` 这几个关键字参数就组成了一个字典 `{'age': 25, 'city': '北京', 'job': '工程师'}`,赋值给了 `details`。

`kwargs` 的位置也很有讲究

`kwargs` 必须放在所有普通位置参数和 `args` 之后。

```python
def another_example(a, args, b, kwargs):
print(f"a: {a}")
print(f"args: {args}")
print(f"b: {b}")
print(f"kwargs: {kwargs}")

调用演示
another_example(1, 2, 3, b=4, city="上海", hobby="阅读")
输出:
a: 1
args: (2, 3)
b: 4
kwargs: {'city': '上海', 'hobby': '阅读'}

注意:b 必须是关键字参数传进来,不能是位置参数,除非是在 args 之前
another_example(1, 2, 3, 4, city="上海") 这样会报错,因为 4 无法确定是给 args 还是 b
```

应用场景:

处理不确定数量的关键字参数: 比如配置选项,或者一些框架的灵活接口。
函数装饰器: 装饰器包裹函数时,经常需要传递被装饰函数可能有的所有关键字参数。
函数调用时的“解包”: `` 同样可以用在函数调用时,把一个字典的键值对“解包”成独立的关键字参数传递进去。

```python
user_profile = {"age": 30, "occupation": "开发者", "email": "test@example.com"}
display_info("赵六", user_profile)
输出:
姓名: 赵六
额外信息:
age: 30
occupation: 开发者
email: test@example.com
```
这里的 `user_profile` 把 `user_profile` 字典里的 `age=30`, `occupation="开发者"`, `email="test@example.com"` “拆开”,变成了 `display_info("赵六", age=30, occupation="开发者", email="test@example.com")`。

`` 和 `` 组合使用:极大的灵活性

你也可以同时使用 `args` 和 `kwargs`,这使得函数可以接收任意数量的位置参数和任意数量的关键字参数。

```python
def powerful_function(first_arg, variadic_args, variadic_kwargs):
print(f"第一个固定参数: {first_arg}")
print(f"其他位置参数: {variadic_args}")
print(f"关键字参数: {variadic_kwargs}")

powerful_function(100, 200, 300, name="Alice", city="London")
输出:
第一个固定参数: 100
其他位置参数: (200, 300)
关键字参数: {'name': 'Alice', 'city': 'London'}
```

总结一下:

`args`: 在函数定义时,用于收集任意数量的位置参数,并将它们放入一个元组。在函数调用时,用于将一个可迭代对象(如列表、元组)的元素解包成多个位置参数。
`kwargs`: 在函数定义时,用于收集任意数量的关键字参数,并将它们放入一个字典。在函数调用时,用于将一个字典的键值对解包成多个关键字参数。

掌握了 `args` 和 `kwargs`,你就掌握了 Python 函数参数传递的“瑞士军刀”,能写出更加灵活、通用、健壮的代码。它们是 Python 动态性和表达力的一个绝佳体现。

网友意见

user avatar

这个问题基本弄清楚了,星号(asterisk)主要在函数定义和函数调用的时候使用。

  1. 函数定义时
    1. 使用单个*会将所有的参数,放入一个元组(tuple)供函数使用。
    2. 使用两个 **会将所有的关键字参数,放入一个字典(dict)供函数使用。
  2. 函数调用时
    1. 在list,tuple,set前加一个星号会把容器中的所有元素解包(unpack)变成位置参数。
    2. 在dict前加一个星号会把字典的键变成位置参数。
    3. 在dict前加两个星号会把字典的键值对变成关键字参数。
      a={'a':'Ass','b':'We','c':'Can'}

具体到描述中的函数:

Aniki(*a)

等同于Aniki("a", "b", "c")

Aniki(**a)

等同于 Aniki(a="Ass", b="We", c="Can")

Aniki(**a,b=(1,2))

等同于 Aniki(a="Ass", b="We", c="Can",b=(1,2))


希望说清楚了。

Stack Overflow上这个问题的回答更全面,提到了星号的其他作用,推荐看一看What does ** (double star/asterisk) and * (star/asterisk) do for parameters?


Python3中新增的两种用法:

  1. Keyword-Only Arguments 仅关键字参数
  2. Extended Iterable Unpacking 扩展迭代解包

仅关键字参数

*args后加入关键字参数,就可以要求这个参数必须以关键字的方式赋值。

       def keyword_only(a, *args, b):     print[a, args, b]     

在调用的时候,必须用关键字的方式赋值。单个星号*也有相同作用,只不过不能接收无限位置参数了。

       def keyword_only(a, *, b):    print[a, args, b]     

扩展迭代解包

许多算法要求以第一个元素剩下的全部 这种方式分割一个序列。即

       first, rest = seq[0], seq[1:]     

现在可以这样:

       first, *rest = seq     

或者这样:

       a, *b, c = seq     

a取得第一个元素,c取得最后一个元素,b取得剩下的全部。

PEP文档:

  1. PEP 3102 -- Keyword-Only Arguments
  2. PEP 3132 -- Extended Iterable Unpacking

可以用这个在线的Python3解释器试一试,Online Python3 Compiler - Online Python3 Editor - Online Python3 IDE - Python3 Coding Online - Practice Python3 Online - Execute Python3 Online - Compile Python3 Online - Run Python3 Online

类似的话题

  • 回答
    这问题问得好,确实,Python 里这两个小东西,`` 和 ``,看似简单,但它们的能耐可大了去,尤其是用在函数定义和调用上,更是能让你的代码变得灵活又强大。咱们这就来捋一捋,把它们说透了。 `args`:收集“散弹”传进来的位置参数想象一下,你写一个函数,本意是想接收几个固定的参数,比如 `def.............
  • 回答
    在 Python 中,`isdigit()` 方法确实只能判断字符串是否全部由数字组成,而且是 非负整数。这意味着它会正确处理 `"123"` 这样的字符串,但对于 `"123"` 或 `"123.45"` 这样的字符串会返回 `False`。这是因为负号 `` 和小数点 `.` 都不是数字字符。那.............
  • 回答
    当你用Python写一个函数来递归地计算斐波那契数列时,你会发现它的速度慢得惊人,尤其是在你需要计算较大的斐波那契数时。这可不是巧合,背后藏着一些深刻的原因,我们来好好掰扯掰扯。想象一下,你想计算 `fib(5)`。按照递归的定义,`fib(5)` 等于 `fib(4)` 加上 `fib(3)`。 .............
  • 回答
    Python 函数的二次封装:让你的代码更优雅、更实用在 Python 的世界里,我们常常需要利用现有的库函数来完成各种任务。然而,原生的函数虽然功能强大,但有时在使用起来可能不够灵活,或者需要额外的配置才能达到我们想要的效果。这时候,“函数二次封装”就成了提升代码质量、提高开发效率的利器。简单来说.............
  • 回答
    这可真是个有趣的问题,关于函数重载,语言设计者们确实各有取舍。不是所有“新语言”都不支持函数重载,比如 C++ 和 Java 这两大主流语言就都提供了这项功能。但是,你提到的 Python, Go, 和 Rust,它们确实都没有原生支持函数重载的机制。这背后其实是这些语言在设计哲学和目标上的不同选择.............
  • 回答
    .......
  • 回答
    Python 作为一种强大的数据科学语言,拥有丰富多样的数据可视化库,为用户提供了从基础绘图到复杂交互式可视化的广泛选择。除了 `matplotlib` 这个被誉为“万能瑞士军刀”的库之外,还有许多其他优秀的库,它们在特定领域、易用性、交互性或美学风格上各有千秋。下面我将详细介绍一些常用的 Pyth.............
  • 回答
    处理百亿行、数十列的数据是一项巨大的挑战,它不仅仅是简单地将数据加载到内存中,而需要一套系统性的策略来克服内存限制、提高处理效率和保证计算的稳定性。Python/Pandas本身在内存受限的情况下处理如此大规模的数据会遇到困难,但我们可以结合Pandas与其他工具和技术来应对。下面将详细讲解Pyth.............
  • 回答
    Python 是一门功能强大且用途广泛的语言,有很多很棒的练手项目可以帮助你学习和巩固知识。我会根据不同的学习阶段和兴趣方向,为你推荐一些值得详细介绍的项目,并说明为什么它们是好的练手项目。在开始之前,你需要具备的基础: Python 基础语法: 变量、数据类型(整型、浮点型、字符串、列表、元组.............
  • 回答
    Python 绝对是一门对面向对象编程 (OOP) 非常友好的语言,并且在很多方面都做得非常出色,让 OOP 的实践变得直观、简洁且强大。但正如所有技术一样,总有改进的空间。下面我将详细阐述 Python 在 OOP 方面的友好性,以及它可能存在的改进空间: Python 对面向对象编程的友好性体现.............
  • 回答
    Python 语言的强制缩进,也就是“代码块”的定义完全依赖于缩进,而不是像许多其他语言那样使用花括号 `{}` 或 `begin/end` 等关键字,这是一个在开发者社区中长期存在争议的话题。 是否是“败笔”,很大程度上取决于个人的编程习惯、对代码可读性的侧重以及所处的开发环境。下面我将详细阐述支.............
  • 回答
    Python 2 和 Python 3 之间存在许多重要的区别,这些区别使得 Python 3 更现代化、更易于使用、更强大。以下是一些主要的区别,我会尽可能详细地解释: 1. `print` 语句与 `print()` 函数Python 2: `print` 是一个语句(statement)。``.............
  • 回答
    Python 在变量的定义和赋值方面,确实与一些其他静态类型语言(例如 C++、Java)存在显著差异,这种差异常常被一些开发者看作是 Python 设计上的一个特点,但将其直接定义为“设计上的缺陷”则需要更深入的分析。要理解这个问题,我们首先需要明确 Python 在变量处理上的核心机制:Pyth.............
  • 回答
    Python 的标准库和第三方库非常丰富,覆盖了从基础操作到复杂应用的各个领域。以下是对这些库的详细分类和介绍,帮助你了解它们的用途和使用场景: 一、Python 标准库(内置模块)Python 的标准库是随 Python 解释器一同安装的,无需额外安装即可使用。以下是常见的分类和示例: 1. 基础.............
  • 回答
    Python 的“黑魔法”通常指的是一些不常见、非传统、或者需要深入理解 Python 底层机制才能掌握的技巧。它们能够让你写出更简洁、更强大、甚至有些“反直觉”的代码。这些“黑魔法”往往能极大地提高开发效率,但也可能降低代码的可读性,因此使用时需要权衡。下面我将尽量详细地介绍一些 Python 的.............
  • 回答
    这个问题嘛,就像问“我该选择披萨还是汉堡?”一样,答案很大程度上取决于你想做什么,以及你对“前景好”的定义。Python和Go,说实话,现在都处于职业生涯的黄金时期,硬要说谁“更好”,实在是个见仁见智的事。不过,咱们可以把它们俩的特点拉出来遛遛,看看哪个更对你的胃口。Python:万金油,社区的拥抱.............
  • 回答
    关于Python学习年龄这件事,我得说,这事儿挺灵活的,不像定个死规矩那样。我身边就有不少朋友,年龄跨度挺大的,都有自己的收获。如果你是还在学校的学生(小学、初中、高中): 小学阶段: 我觉得这得看孩子的兴趣和家长引导了。如果孩子本身就对电脑操作、小游戏制作、或者一些逻辑思维的游戏比较感兴趣,那.............
  • 回答
    在 Python 中,`with ... as ...` 语句主要用于资源管理,特别是文件的打开和关闭,或者其他需要进行清理操作的对象。它的核心目的是 确保无论代码块如何退出(正常结束、抛出异常),都会执行清理操作。如何理解 "跳出" `with...as` 语句?这里的“跳出”可以从两个层面来理解.............
  • 回答
    没问题,我来给你详细讲讲如何在 Python 中实现“按分类转换列表”。这个需求很常见,比如我们有一个包含各种类型数据的列表,我们想根据数据的类型把它们分成不同的子列表。咱们就用一个实际的例子来讲解,这样更容易理解。假设我们有一个混合类型的列表,里面有数字、字符串、布尔值等等,我们想把它们分别归类到.............
  • 回答
    在 Python 中,`len(x)` 并不是一个用于补零的函数,它实际上是用来获取序列(如字符串、列表、元组等)长度的。你提到的“利用 `len(x)` 补零”可能是在说,你需要根据某个序列的长度,将另一个序列(通常是数字或字符串)进行补零操作,使其达到一个特定的长度。核心概念:为什么是补零?补零.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有