Python 教程 / 函数参数

函数参数

Python的函数参数非常灵活,除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数接口简单又强大。

位置参数

位置参数是最基本的参数形式,调用时按照参数定义的顺序依次传入。

┌─────────────────────────────────────────────────────────────────────┐
│                      位置参数调用过程                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  def power(x, n):          # x, n 是位置参数                        │
│      result = 1                                                   │
│      while n > 0:                                                   │
│          result *= x                                                │
│          n -= 1                                                    │
│      return result                                                 │
│                                                                     │
│  调用 power(5, 3):                                                │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  传入顺序:                                                    │   │
│  │                                                             │   │
│  │   power(5, 3)                                              │   │
│  │        │    │                                               │   │
│  │        ▼    ▼                                               │   │
│  │   x=5, n=3  ──▶ 按位置匹配                                 │   │
│  │                                                             │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
# 位置参数示例
def power(x, n):
    """计算 x 的 n 次方"""
    result = 1
    while n > 0:
        result *= x
        n -= 1
    return result

print(power(2, 3))   # 8 (2³ = 2*2*2)
print(power(5, 2))   # 25 (5² = 5*5) 

默认参数

为参数设置默认值,调用时可以省略该参数。

┌─────────────────────────────────────────────────────────────────────┐
│                      默认参数工作原理                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  def power(x, n=2):        # n=2 是默认参数                        │
│      return x ** n                                                  │
│                                                                     │
│  调用方式:                                                          │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  power(5)        ──▶ power(5, 2)      使用默认值 n=2       │   │
│  │  power(5, 3)     ──▶ power(5, 3)      覆盖默认值 n=3       │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  好处: 调用简单,大多数情况使用默认值的场景无需传参                   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
# 默认参数示例
def greet(name, greeting="你好", punctuation="!"):
    return f"{greeting},{name}{punctuation}"

# 省略默认参数
print(greet("张三"))                 # 你好,张三!
# 覆盖部分默认参数
print(greet("李四", "早上好"))      # 早上好,李四!
# 覆盖所有默认参数
print(greet("王五", "晚上好", "~")) # 晚上好,王五~ 
默认参数必须指向不可变对象

如果默认参数使用可变对象,可能导致意外结果:

# 错误示例
def bad_func(items=[]):
    items.append(1)
    return items

print(bad_func())  # [1]
print(bad_func())  # [1, 1]  -- 错误!应该每次都是 [1]

# 正确示例
def good_func(items=None):
    if items is None:
        items = []
    items.append(1)
    return items

print(good_func())  # [1]
print(good_func())  # [1]  -- 正确! 

可变参数 *args

使用*args可以接收任意数量的位置参数,这些参数在函数内部被封装成一个元组。

┌─────────────────────────────────────────────────────────────────────┐
│                      *args 工作原理                                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  def func(*args):                                                  │
│      print(args)                                                   │
│                                                                     │
│  调用 func(1, 2, 3):                                               │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                                                             │   │
│  │   传入: func(1, 2, 3)                                      │   │
│  │            │    │    │                                      │   │
│  │            ▼    ▼    ▼                                      │   │
│  │   args = (1, 2, 3)    ← 被打包成元组                        │   │
│  │                                                             │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  好处: 可以接收任意数量的参数,0个也可以                             │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
# 计算平方和
def calc_sum_of_squares(*args):
    """计算所有参数的平方和"""
    total = 0
    for n in args:
        total += n * n
    return total

print(calc_sum_of_squares(1, 2, 3))     # 14 (1+4+9)
print(calc_sum_of_squares(1, 2))           # 5 (1+4)
print(calc_sum_of_squares())                # 0 

解包参数传入 *args

如果已经有了一个列表或元组,可以在调用时用*解包传入。

Python
def calc_sum_of_squares(*args):
    return sum(n * n for n in args)

# 方式1: 直接传入
print(calc_sum_of_squares(1, 2, 3))     # 14

# 方式2: 解包列表/元组传入
numbers = [1, 2, 3]
print(calc_sum_of_squares(*numbers))   # 14  -- 等同于 calc_sum_of_squares(1, 2, 3) 

关键字参数 **kwargs

使用**kwargs可以接收任意数量的关键字参数,这些参数在函数内部被封装成一个字典。

┌─────────────────────────────────────────────────────────────────────┐
│                     **kwargs 工作原理                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  def func(**kwargs):                                               │
│      print(kwargs)                                                  │
│                                                                     │
│  调用 func(name="张三", age=25):                                    │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                                                             │   │
│  │   传入: func(name="张三", age=25)                           │   │
│  │              │           │                                  │   │
│  │              ▼           ▼                                  │   │
│  │   kwargs = {"name": "张三", "age": 25}  ← 被打包成字典      │   │
│  │                                                             │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  特点:                                                              │
│  • 关键字参数是 key=value 形式                                      │
│  • 在函数内部收到的是 dict                                           │
│  • 可以传入0个或任意多个                                             │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
# 打印用户信息
def print_user_info(**kwargs):
    """打印所有关键字参数"""
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print("用户信息:")
print_user_info(name="张三", age=25, city="北京")
# 输出:
# name: 张三
# age: 25
# city: 北京 

解包字典传入 **kwargs

如果已经有一个字典,可以在调用时用**解包传入。

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

# 方式1: 直接传入
print_user_info(name="张三", age=25)

# 方式2: 解包字典传入
user = {"name": "李四", "age": 30, "city": "上海"}
print_user_info(**user)  # 等同于 print_user_info(name="李四", age=30, city="上海") 

命名关键字参数

有时候需要限制关键字参数的名字,可以用命名关键字参数。

┌─────────────────────────────────────────────────────────────────────┐
│                    命名关键字参数语法                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  普通关键字参数 (可以传入任意名字):                                  │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ def func(**kwargs):                                        │   │
│  │     # kwargs 可以是任意 key                                 │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  命名关键字参数 (限制只能传入特定名字):                              │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ def func(*, city, job):                                    │   │
│  │     # 必须使用 city 和 job 作为参数名                        │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  或使用 *args 之后:                                                 │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ def func(*args, city, job):                                │   │
│  │     # *args 之后的 city, job 是命名关键字参数                 │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
# 命名关键字参数示例
def register(name, *, city, job):
    print(f"姓名: {name}")
    print(f"城市: {city}")
    print(f"职业: {job}")

# 必须使用参数名传入
register("张三", city="北京", job="工程师")
# register("李四", "上海", "医生")  # 错误!city和job必须用关键字参数

# 命名关键字参数也可以有默认值
def register2(name, *, city="北京", job):
    print(f"{name} - {city} - {job}")

register2("李四", job="医生")      # 李四 - 北京 - 医生 (使用city默认值) 

参数组合图解

┌─────────────────────────────────────────────────────────────────────┐
│                    Python 参数组合规则                               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  定义顺序 (从左到右):                                               │
│                                                                     │
│   1. 位置参数        (如: x, y)                                     │
│   2. *args          (可变位置参数)                                  │
│   3. 默认参数        (如: a=1, b=2)                                 │
│   4. 命名关键字参数   (如: *, city, job)                            │
│   5. **kwargs        (可变关键字参数)                               │
│                                                                     │
│  简化记忆:                                                           │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  位置参数 → *args → 默认参数 → 命名关键字参数 → **kwargs     │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  示例:                                                              │
│  def func(a, b, *args, c=1, d=2, **kwargs):                        │
│      # a, b      : 位置参数                                         │
│      # *args     : 可变位置参数                                     │
│      # c=1, d=2  : 默认参数                                        │
│      # **kwargs  : 可变关键字参数                                   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
# 完整参数组合示例
def complex_func(pos1, pos2, *args, default_val=100, named_key="default", **kwargs):
    print(f"位置参数: pos1={pos1}, pos2={pos2}")
    print(f"可变参数: {args}")
    print(f"默认参数: default_val={default_val}")
    print(f"命名关键字参数: named_key={named_key}")
    print(f"其他关键字参数: {kwargs}")

# 调用示例
complex_func(1, 2, 3, 4, 5, default_val=999, named_key="test", extra=666)
# 输出:
# 位置参数: pos1=1, pos2=2
# 可变参数: (3, 4, 5)
# 默认参数: default_val=999
# 命名关键字参数: named_key=test
# 其他关键字参数: {'extra': 666} 

解包调用

使用*解包列表,使用**解包字典。

Python
def point(x, y, z):
    return (x, y, z)

# 用列表解包调用
coords = [1, 2, 3]
print(point(*coords))       # (1, 2, 3)  -- 等同于 point(1, 2, 3)

# 用字典解包调用
params = {"x": 10, "y": 20, "z": 30}
print(point(**params))      # (10, 20, 30)  -- 等同于 point(x=10, y=20, z=30)

# 组合使用
def calc(a, b, c=0, *args, **kwargs):
    print(f"a={a}, b={b}, c={c}, args={args}, kwargs={kwargs}")

nums = [1, 2, 3]
opts = {"extra1": 100, "extra2": 200}
calc(*nums, **opts)  # a=1, b=2, c=3, args=(), kwargs={'extra1': 100, 'extra2': 200} 

章节测验

问题1: 下面代码的输出是什么?

def func(*args, **kwargs):
    print(args, kwargs)

func(1, 2, a=3, b=4) 

问题2: 以下哪个是定义命名关键字参数的方式?

问题3: 默认参数为什么不能使用可变对象?

问题4: 调用 func(*[1,2,3], ** {'a':4}) 相当于传入什么?

练习题

练习1: 改造乘积函数

将只接受两个参数的乘积函数,改造成可以接受任意数量参数的版本。

# 原函数
def mul(x, y):
    return x * y

# 改造后可以这样调用:
# mul(2) = 2
# mul(2, 3) = 6
# mul(2, 3, 4) = 24
# mul(2, 3, 4, 5) = 120 
练习2: 关键字参数收集

编写一个函数,接收姓名和其他任意信息,格式化为地址字符串。

格式: "姓名: xxx, 城市: xxx, 职业: xxx, ..."
# 如: format_address("张三", city="北京", age=25, job="工程师")
# 输出: "姓名: 张三, 城市: 北京, 职业: 工程师" 
练习3: 参数解包调用

使用解包调用实现数组求和。

numbers = [1, 2, 3, 4, 5]
# 使用 *numbers 调用 sum_all 函数求和 
🐍 Python 在线代码编辑器
📝 运行结果