Python 编程技术:函数的参数

Posted on May 2, 2025

在 Python 中,函数的参数传递非常灵活。Python 是一种动态类型语言,因此函数参数不需要声明类型,传入什么类型的值都可以。Python 的函数参数主要分为以下几种类型:

基础参数类型

位置参数(Positional Arguments)

这是最常见的参数类型。调用函数时,按照参数定义的顺序依次传入对应的值。

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

greet("Alice", 25)  # 正确

注意:如果传参顺序不对,可能导致逻辑错误。

关键字参数(Keyword Arguments)

在调用函数时,可以使用 参数名=值 的方式传参,这样可以不考虑参数的顺序。

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

greet(age=30, name="Bob")  # 正确,顺序无关

默认参数(Default Arguments)

定义函数时可以为参数指定默认值。如果调用时没有传该参数,则使用默认值。

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

greet("Charlie")         # 输出: Charlie is 18 years old.
greet("David", 22)       # 输出: David is 22 years old.

注意

  • 虽然函数的参数类型有很多种,但是一个参数传递给函数的方式有且只有两种:位置传递和关键字传递。在没有特殊限制(后面会讲到)的情况下,一个位置参数可以被当作关键字参数传递,一个关键字参数也能被当作位置参数传递:

    def greet(name, age=18):
        print(f"{name} is {age} years old.")
    
    greet("Alice", 25) # 都按位置传递,输出: Alice is 25 years old.
    greet(name="Bob", age=30) # 都按关键字传递,输出: Bob is 30 years old.
    

    但是,一个以关键字传递的参数必须出现在位置传递的参数之后

    def greet(name, age=18):
        print(f"{name} is {age} years old.")
    
    greet(name=8, "Jane") 
    # SyntaxError: positional argument follows keyword argument
    
  • 默认参数只在函数定义时求值一次,不要使用可变对象作为默认参数(如列表或字典),否则会导致意外行为。

    错误示例:

    def add_item(item, lst=[]):
        lst.append(item)
        return lst
    
    print(add_item(1))  # [1]
    print(add_item(2))  # [1, 2]  ← 意外行为!
    

    推荐写法:

    def add_item(item, lst=None):
        if lst is None:
            lst = []
        lst.append(item)
        return lst
    

可变数量参数(Variable-length Arguments)

用于接收任意数量的位置参数或关键字参数。

*args - 接收任意数量的位置参数(打包成元组)

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

print(sum_all(1, 2, 3))   # 输出: 6
print(sum_all(4, 5))      # 输出: 9

**kwargs - 接收任意数量的关键字参数(打包成字典)

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

print_info(name="Eve", age=28, city="Shanghai")
# 输出:
# name: Eve
# age: 28
# city: Shanghai

仅限关键字参数(Keyword-only Arguments)

从 Python 3 开始支持“强制关键字参数”,即某些参数必须通过关键字传参,不能按位置传参。

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

greet(name="Frank", age=30)   # 正确
greet("Frank", 30)             # 报错 TypeError

也可以在 *args 后面添加关键字参数,使其成为仅限关键字参数:

def func(a, b, *args, c, d):
    print(f"a={a}, b={b}, args={args}, c={c}, d={d}")

func(1, 2, 3, 4, c=5, d=6)
# 输出: a=1, b=2, args=(3, 4), c=5, d=6

仅限位置参数(Positional-only Arguments)

从 Python 3.8 开始,支持“仅限位置参数”,即某些参数只能通过位置传参,不能使用关键字传参。这种参数在函数定义中使用 / 分隔符来指定:位于 / 左侧的参数是仅限位置参数。

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

greet("Helen", 26)         # 正确
greet(name="Helen", age=26) # 报错 TypeError: greet() got some positional-only arguments passed as keyword arguments: 'name, age'

更复杂的示例:混合使用位置参数和关键字参数

可以在函数定义中同时使用 /* 来明确哪些参数是仅限位置的,哪些是仅限关键字的:

def func(a, b, /, c, d, *, e, f):
    print(f"a={a}, b={b}, c={c}, d={d}, e={e}, f={f}")

func(1, 2, 3, d=4, e=5, f=6)  # 正确调用方式
# a 和 b 是仅限位置参数
# c 可以按位置或关键字传参
# d 可以按位置或关键字传参
# e 和 f 是仅限关键字参数

注意:/ 表示仅限位置参数的结束;* 表示仅限关键字参数的开始。

使用场景

  • 当需要 API 的使用者严格按照顺序传递参数时;

  • 提高接口清晰度,避免歧义(如参数名可能重复或含糊);

  • 某些内置函数为了保持与 C 实现的一致性,也需要仅限位置参数。

参数解包(Argument Unpacking)

可以在调用函数时使用 *** 来解包序列或字典。

使用 * 解包列表/元组

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

nums = [3, 4]
print(add(*nums))  # 等效于 add(3, 4)

使用 ** 解包字典

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

info = {"name": "Grace", "age": 27}
greet(**info)  # 等效于 greet(name="Grace", age=27)

总结

参数类型 关键字/符号 是否必须 特点说明
位置参数 必须按顺序传入
关键字参数 参数名=值 可以打乱顺序传参
默认参数 参数=默认值 有默认值,可省略
可变位置参数 *args 接收多个位置参数,打包为元组
可变关键字参数 **kwargs 接收多个关键字参数,打包为字典
仅限关键字参数 *后定义 必须用关键字传参
仅限位置参数 /后定义 必须用位置传参