Python--函数的参数传递

132 阅读4分钟

一、Python 函数参数传递的核心概念

首先要明确:Python 中一切皆对象,参数传递的本质是「对象引用传递」(可以理解为 “传递的是对象的地址”),而不是简单的 “值传递” 或 “引用传递”。

关键区别:

  • 不可变对象(如 int、str、tuple):修改时会创建新对象,原对象不变
  • 可变对象(如 list、dict、set):修改时会直接操作原对象,原对象会变化

二、参数传递的 4 种基础形式

下面从简单到复杂,介绍 Python 函数参数的 4 种常用传递方式:

1. 位置参数(必选参数)

最基础的参数形式,必须按顺序传递,且数量要与函数定义一致。

python

运行

# 定义函数:计算两个数的和(a、b是位置参数)
def add(a, b):
    return a + b

# 调用函数:按位置顺序传递参数
result1 = add(3, 5)
print(result1)  # 输出:8

# 错误示例1:参数数量不匹配
# add(3)  # 报错:缺少1个位置参数

# 错误示例2:顺序错误(结果不符合预期)
result2 = add(5, 3)
print(result2)  # 输出:8(这里碰巧结果一样,换个场景就会出错)

2. 关键字参数

通过「参数名 = 值」的形式传递,无需按顺序,更清晰易懂。

python

运行

# 定义函数:计算矩形面积
def rectangle_area(length, width):
    return length * width

# 关键字参数调用(顺序可任意)
area1 = rectangle_area(length=5, width=3)
area2 = rectangle_area(width=3, length=5)
print(area1)  # 输出:15
print(area2)  # 输出:15

# 混合使用:位置参数在前,关键字参数在后(必须遵守这个顺序)
area3 = rectangle_area(5, width=3)
print(area3)  # 输出:15

# 错误示例:关键字参数不能在位置参数前面
# rectangle_area(width=3, 5)  # 报错

3. 默认参数

定义函数时给参数指定默认值,调用时可省略该参数(使用默认值)。

python

运行

# 定义函数:打招呼(name是必选参数,greeting是默认参数)
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

# 省略默认参数(使用默认值"Hello")
print(greet("Alice"))  # 输出:Hello, Alice!

# 覆盖默认参数(使用自定义值)
print(greet("Bob", "Hi"))  # 输出:Hi, Bob!
print(greet("Charlie", greeting="Good morning"))  # 关键字形式覆盖

# 注意:默认参数必须放在位置参数后面
# def greet(greeting="Hello", name):  # 报错

⚠️ 重要提醒:默认参数的默认值最好是不可变对象(如 int、str、None),不要用 list、dict 等可变对象(会导致意外结果)。

python

运行

# 错误示例:默认参数用可变对象list
def bad_func(a, b=[]):
    b.append(a)
    return b

print(bad_func(1))  # 输出:[1]
print(bad_func(2))  # 输出:[1, 2](不是预期的[2])

# 正确示例:用None作为默认值,在函数内创建可变对象
def good_func(a, b=None):
    if b is None:
        b = []  # 每次调用都创建新的list
    b.append(a)
    return b

print(good_func(1))  # 输出:[1]
print(good_func(2))  # 输出:[2](符合预期)

4. 可变参数(*args 和 **kwargs)

用于处理不确定数量的参数,灵活度极高。

(1)*args:接收任意数量的「位置参数」,打包成元组(tuple)

python

运行

# 定义函数:计算任意多个数的和
def sum_all(*args):
    print(type(args))  # 输出:<class 'tuple'>
    total = 0
    for num in args:
        total += num
    return total

# 调用:传递任意数量的位置参数
print(sum_all(1, 2, 3))  # 输出:6
print(sum_all(10, 20, 30, 40))  # 输出:100
print(sum_all())  # 输出:0(允许传递0个参数)

# 解包传递(用*把列表/元组解包成位置参数)
nums = [1, 2, 3, 4, 5]
print(sum_all(*nums))  # 输出:15(等价于sum_all(1,2,3,4,5))
(2)**kwargs:接收任意数量的「关键字参数」,打包成字典(dict)

python

运行

# 定义函数:打印用户信息
def print_user(**kwargs):
    print(type(kwargs))  # 输出:<class 'dict'>
    for key, value in kwargs.items():
        print(f"{key}: {value}")

# 调用:传递任意数量的关键字参数
print_user(name="Alice", age=25, city="Beijing")
# 输出:
# name: Alice
# age: 25
# city: Beijing

# 解包传递(用**把字典解包成关键字参数)
user_info = {"name": "Bob", "age": 30, "city": "Shanghai"}
print_user(**user_info)
# 输出:
# name: Bob
# age: 30
# city: Shanghai
(3)*args 和 **kwargs 同时使用

通常用于接收所有类型的参数,顺序必须是:位置参数 → *args → 关键字参数 → **kwargs

python

运行

def flexible_func(a, b, *args, c=0, **kwargs):
    print(f"必选参数a: {a}, b: {b}")
    print(f"可变位置参数args: {args}")
    print(f"默认关键字参数c: {c}")
    print(f"可变关键字参数kwargs: {kwargs}")

# 调用示例
flexible_func(1, 2, 3, 4, c=5, d=6, e=7)
# 输出:
# 必选参数a: 1, b: 2
# 可变位置参数args: (3, 4)
# 默认关键字参数c: 5
# 可变关键字参数kwargs: {'d': 6, 'e': 7}

三、参数传递的核心规则总结

  1. 传递本质:Python 是「对象引用传递」,不可变对象修改会创建新对象,可变对象修改会影响原对象。
  2. 参数顺序:定义函数时必须遵循:位置参数 → 默认参数 → *args → 关键字参数 → **kwargs
  3. 调用规则:调用时,位置参数必须在关键字参数前面。
  4. 灵活传递:*args 接收任意位置参数(元组),**kwargs 接收任意关键字参数(字典),支持解包传递。
  5. 默认参数陷阱:默认参数不要用可变对象(list、dict 等),改用 None 在函数内初始化