整体说明
- 在 Python 中,
*和**的主要用途有两个- 作为解包操作符 :用于解包(unpacking)序列或字典
- 在函数定义和调用时处理可变参数
*用于接收可变数量的位置参数,被称为 “可变位置参数”(variable positional arguments)**用于接收可变数量的关键字参数,被称为 “可变关键字参数”(variable keyword arguments)
*解包操作(序列解包)
*操作符用于解包可迭代对象(如列表、元组、字符串、生成器等),将其元素单独提取出来
函数调用时解包
- 函数调用时解包参数 Demo:
1
2
3
4
5def add(a, b, c):
return a + b + c
numbers = [1, 2, 3]
result = add(*numbers) # 等同于 add(1, 2, 3)
print(result) # 输出: 6
在赋值语句中解包
- 赋值语句中解包 Demo
1
2
3
4a, *b, c = [1, 2, 3, 4, 5]
print(a) # 输出: 1
print(b) # 输出: [2, 3, 4]
print(c) # 输出: 5
合并列表或元组
- 合并列表或元组时解包 Demo
1
2
3
4
5
6
7
8# 合并列表
list1 = [1, 2]
list2 = [3, 4]
merged = [*list1, *list2] # 等同于 [1, 2, 3, 4]
# 合并元组和列表
t = (1, 2)
l = [3, 4]
merged = [*t, *l] # 等同于 [1, 2, 3, 4]
**解包操作(字典解包)
**操作符用于解包字典 ,将其键值对作为参数传递给函数
在函数调用时解包字典
- 函数调用时解包 Demo:
1
2
3
4
5def greet(name, age):
return f"Hello {name}, you are {age} years old."
person = {"name": "Alice", "age": 30}
message = greet(**person) # 等同于 greet(name="Alice", age=30)
print(message) # 输出: "Hello Alice, you are 30 years old."
合并字典(Python 3.5 以上版本才能使用)
- 合并字典解包 Demo:
1
2
3dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
merged = {**dict1, **dict2} # 等同于 {"a": 1, "b": 2, "c": 3, "d": 4}
*args作为函数参数(可变位置参数)
*args用于接收任意数量的位置参数(也称为非关键字参数),并将它们作为元组处理*args作为函数参数 Demo1
2
3
4
5
6
7def sum_numbers(*args):
total = 0
for num in args:
total += num
return total
result = sum_numbers(1, 2, 3, 4) # args = (1, 2, 3, 4)
print(result) # 输出: 10说明:
args是元组类型(解包时可以解所有序列,包括列表、元组、字符串、生成器等)- 可以不传递参数,此时
args为空元组 - 定义时
*args必须放在普通参数和**kwargs之间(如def func(a, *args, **kwargs))
**kwargs作为函数参数(可变关键字参数)
**kwargs用于接收任意数量的关键字参数 ,并将它们作为字典处理**kwargs作为函数参数 Demo:1
2
3
4
5
6
7
8def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Bob", age=25, city="New York")
# 输出:
# name: Bob
# age: 25
# city: New York说明:
kwargs是字典类型- 可以不传递参数,此时
kwargs为空字典 - 必须放在参数列表的最后(如
def func(a, *args, b=1, **kwargs))
组合使用*args和**kwargs
函数可以同时接受
*args和**kwargs,顺序必须是:def func(positional, *args, **kwargs)组合使用
*args和**kwargs的 Demo:1
2
3
4
5
6
7
8
9def example(a, *args, **kwargs):
print(f"Positional: {a}") # 必传参数
print(f"Args: {args}") # 可选的位置参数
print(f"Kwargs: {kwargs}") # 可选的关键字参数
example(1, 2, 3, x=4, y=5)
# 输出:
# Positional: 1
# Args: (2, 3)
# Kwargs: {'x': 4, 'y': 5}说明:
普通参数也可以不传递,此时只剩下
*args和**kwargs两种参数在使用了
**kwargs时,也可以继续使用关键字参数,但必须放到*args和**kwargs之间1
2
3
4
5
6
7def example(a, *args, y=10, **kwargs)
# def example(a, *args, **kwargs, y=10) # error
```
* 注:函数调用时,关键字参数和`**kwargs`的顺序没有限制,但位置参数的位置不能变化
```python
def example(a, *args, y=10, **kwargs)
def example(1, 2, 3, x=4, y=5, y=10) # 关键字参数 y 的顺序变化是可以的深入理解:放到
*args和**kwargs之间的参数,必须按照关键字参数使用(定义时可以位置式的样子定义)1
2
3def example(a, *args, n, **kwargs)
example(1, 2, 3, n=10, x=4, y=5) # 正确,n 应该指定关键字参数使用
# example(1, 2, 3, 10, x=4, y=5) # 报错,n 应该指定关键字参数使用
常见用法
函数包装器(Decorator)透传参数
- 函数包装器透传参数 Demo:
1
2
3
4
5
6
7
8
9
10
11def my_decorator(func):
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs) # 传递所有参数给原函数
print("After function call")
return result
return wrapper
def add(a, b):
return a + b
继承中的参数透传
- 继承时参数透传 Demo:
1
2
3
4
5
6
7
8
9
10class Parent:
def __init__(self, name, **kwargs):
self.name = name
class Child(Parent):
def __init__(self, age, *args, **kwargs):
super().__init__(*args, **kwargs) # 传递剩余参数给父类
self.age = age
c = Child(age=10, name="Alice")
使用注意事项
*args是非关键字参数(也称为位置参数),对应参数args为元组类型,可表示任何多个无名参数**kwargs是关键字参数 ,对应参数kwargs为字典(dict)类型,可表示任何多个命名参数顺序必须是:1)普通参数;2)
*args;3)**kwargs的形式- 举例:
def func(a, *args, **kwargs) - 其中普通参数、
*args和**kwargs三个参数都是可选的,可以丢弃任意一个,但是相对顺序必须保障 - 放在
*args和**kwargs之间的参数一定是关键字参数
- 举例:
将序列解包为函数参数时要保证参数数量匹配 :
1
2
3
4def func(a, b):
return a + b
args = [1, 2, 3]
func(*args) # 报错:TypeError,参数数量不匹配将字典解包为函数参数时要保证键名匹配 :
1
2
3
4def func(name, age):
pass
kwargs = {"name": "Alice", "city": "NY"} # 键名不匹配
func(**kwargs) # 报错:TypeError,'city' 不是有效参数
附录:特殊用法指定参数为关键字参数
- 如果在函数定义时使用
*,则后面的所有参数必须通过关键字形式传入 - 举例:
1
2
3# 调用 f 函数时,b 和 c 必须使用关键字传入,否则出错
def f(a, *, b=1, c=None)
pass