卡码笔记-最强八股文
首页
计算机基础
Python
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
大模型Github (opens new window)
代码随想录 (opens new window)
首页
计算机基础
Python
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
大模型Github (opens new window)
代码随想录 (opens new window)
  • 本栏必读

    • Python面试题专栏介绍
    • Python学习路线
    • Python零基础入门课
  • 基础语法

  • 函数、作用域与模块

    • Python函数参数是值传递还是引用传递?
    • 位置参数、关键字参数、*args和**kwargs怎么用?
      • 简要回答
      • 详细回答
      • 知识拓展
    • Python默认参数为什么不能随便使用列表和字典?
    • Python中的匿名函数、map、filter和reduce怎么用?
    • Python的LEGB作用域是什么?
    • global和nonlocal有什么区别?
    • 什么是闭包?闭包中的变量为什么会出现延迟绑定?
    • Python模块和包是什么?import是怎么工作的?
  • 面向对象

  • 进阶语法与语言机制

# 位置参数、关键字参数、*args和**kwargs怎么用?

面试官问:"Python函数参数中的*args和**kwargs是什么?什么时候用?"

很多人只知道"*args接收多余的位置参数,**kwargs接收多余的关键字参数",但说不清楚调用时如何匹配、定义时如何限制参数形式,以及解包时会发生什么。

# 简要回答

Python函数参数分为位置参数、关键字参数、可变位置参数*args、可变关键字参数**kwargs,以及仅限位置参数和仅限关键字参数。

位置参数按顺序匹配,调用时按位置传值或用参数名指定。关键字参数必须用参数名传值。*args收集多余的位置参数到元组,**kwargs收集多余的关键字参数到字典。

调用时,可以用*解包序列为位置参数,用**解包字典为关键字参数。

定义时,单独的/之前的参数只能按位置传递,单独的*之后的参数只能按关键字传递。

# 详细回答

# 位置参数与关键字参数

def greet(name, age):
    print(f"{name} is {age} years old")

greet("Alice", 25)         # 位置传递
greet(age=25, name="Alice") # 关键字传递
greet("Alice", age=25)     # 混合传递,位置参数必须在前
1
2
3
4
5
6

位置参数按顺序匹配,关键字参数按名字匹配。 混合传递时,位置参数必须在关键字参数之前。

# *args收集多余位置参数

def sum_all(*args):
    return sum(args)

print(sum_all(1, 2, 3))      # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
1
2
3
4
5

*args把所有多余的位置参数收集成一个元组。函数内可以通过args访问这个元组。

# **kwargs收集多余关键字参数

def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Bob", age=30, city="Beijing")
# name: Bob
# age: 30
# city: Beijing
1
2
3
4
5
6
7
8

**kwargs把所有多余的关键字参数收集成一个字典。函数内可以通过kwargs访问这个字典。

# 同时使用多种参数

函数参数的定义顺序必须遵守:

def func(pos1, pos2, /, pos_or_kw, *args, kw_only, **kwargs):
    pass
1
2
位置 参数类型 说明
/之前 仅限位置参数 只能按位置传递
/之后、*args之前 位置或关键字参数 可以按位置或关键字传递
*args 可变位置参数 收集多余位置参数
*args之后、**kwargs之前 仅限关键字参数 只能按关键字传递
**kwargs 可变关键字参数 收集多余关键字参数

示例:

def example(a, b, /, c, d, *args, e, f=10, **kwargs):
    print(f"a={a}, b={b}, c={c}, d={d}")
    print(f"args={args}")
    print(f"e={e}, f={f}")
    print(f"kwargs={kwargs}")

example(1, 2, 3, 4, 5, 6, e=7, f=8, g=9, h=10)
# a=1, b=2, c=3, d=4
# args=(5, 6)
# e=7, f=8
# kwargs={'g': 9, 'h': 10}
1
2
3
4
5
6
7
8
9
10
11

a和b必须按位置传递,c和d可以按位置或关键字传递,5和6被*args收集,e和f必须用关键字传递,g和h被**kwargs收集。

Python函数参数匹配流程

# 仅限关键字参数

单独的*之后的参数只能用关键字传递:

def create_user(name, *, email, age):
    return {"name": name, "email": email, "age": age}

user = create_user("Alice", email="alice@example.com", age=25)
# 正确

user = create_user("Alice", "alice@example.com", 25)
# TypeError: create_user() takes 1 positional argument but 3 were given
1
2
3
4
5
6
7
8

这种设计强制调用方明确参数含义,提高可读性。

# 仅限位置参数

单独的/之前的参数只能按位置传递:

def divide(a, b, /):
    return a / b

print(divide(10, 2))  # 5.0

print(divide(a=10, b=2))
# TypeError: divide() got some positional-only arguments passed as keyword arguments: 'a, b'
1
2
3
4
5
6
7

仅限位置参数是Python 3.8引入的语法,用于保护参数名不被暴露,允许后续修改参数名而不破坏调用方代码。

# 参数解包

调用时可以用*解包序列,用**解包字典:

def add(a, b, c):
    return a + b + c

values = [1, 2, 3]
print(add(*values))  # 6,等价于add(1, 2, 3)

params = {"a": 1, "b": 2, "c": 3}
print(add(**params))  # 6,等价于add(a=1, b=2, c=3)
1
2
3
4
5
6
7
8

解包时,序列长度必须与位置参数数量匹配,字典的键必须与参数名匹配。

# 知识拓展

Q1:*args和**kwargs的名字可以改吗?

可以。*和**是语法,args和kwargs只是约定俗成的名字。可以写成*numbers或**options,但不建议改,因为会降低代码可读性。

Q2:为什么*args必须在**kwargs之前?

因为调用时位置参数必须在关键字参数之前。*args收集位置参数,**kwargs收集关键字参数,定义顺序必须匹配调用顺序。

Q3:如何限制*args或**kwargs的内容?

函数内检查:

def create_user(*args, **kwargs):
    if len(args) > 0:
        raise TypeError("create_user() takes 0 positional arguments")
    allowed_keys = {"name", "email", "age"}
    for key in kwargs:
        if key not in allowed_keys:
            raise TypeError(f"Unexpected keyword argument: {key}")
1
2
3
4
5
6
7

或者改用明确参数,不用**kwargs。

Q4:调用时能同时用*和**解包吗?

可以:

args = [1, 2]
kwargs = {"c": 3}
print(add(*args, **kwargs))  # 6
1
2
3

但注意不要重复传递同一个参数,否则会抛出TypeError。

Q5:什么时候用*args和**kwargs?

  • 包装其他函数时,用于透传参数。
  • 需要接受任意数量参数时(如print、max)。
  • 写装饰器时,保持被装饰函数的签名。

不要滥用。能用明确参数就用明确参数,提高可读性和IDE提示能力。

Last Updated: 10/13/2026, 5:57:00 PM

← Python函数参数是值传递还是引用传递? Python默认参数为什么不能随便使用列表和字典? →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪