Python 中的 *args 和 **kwargs


Python 中的 *args**kwargs 是在函数定义中使用的特殊语法,它们允许函数接受不定数量的参数。它们是处理函数灵活性的强大工具。


1. *args (星号 args)

*args 允许函数接受任意数量的位置参数(positional arguments)。当你在函数定义中使用 *args 时,它会将所有传递给函数的额外位置参数收集到一个元组(tuple) 中。

  • args 只是一个约定俗成的名字:你可以用任何其他合法的变量名代替 args(例如 *numbers),但 args 是最常用的惯例。
  • 星号 * 是关键:它告诉 Python 将所有额外的位置参数打包成一个元组。

示例:

def sum_all_numbers(*args):
    """
    这个函数可以接受任意数量的数字参数,并返回它们的和。
    """
    print(f"args type: {type(args)}")
    print(f"args content: {args}")
    total = 0
    for num in args:
        total += num
    return total

print(sum_all_numbers(1, 2))
print(sum_all_numbers(1, 2, 3, 4, 5))
print(sum_all_numbers()) # 也可以不传参数

输出:

args type: <class 'tuple'>
args content: (1, 2)
3
args type: <class 'tuple'>
args content: (1, 2, 3, 4, 5)
15
args type: <class 'tuple'>
args content: ()
0

2. **kwargs (双星号 kwargs)

**kwargs 允许函数接受任意数量的关键字参数(keyword arguments)。当你在函数定义中使用 **kwargs 时,它会将所有传递给函数的额外关键字参数收集到一个字典(dictionary) 中。

  • kwargs 也是一个约定俗成的名字:你可以用任何其他合法的变量名代替 kwargs(例如 **config),但 kwargs 是最常用的惯例。
  • 双星号 ** 是关键:它告诉 Python 将所有额外的关键字参数打包成一个字典。

示例:

def print_user_info(**kwargs):
    """
    这个函数可以接受任意数量的关键字参数,并打印用户信息。
    """
    print(f"kwargs type: {type(kwargs)}")
    print(f"kwargs content: {kwargs}")
    if "name" in kwargs:
        print(f"Name: {kwargs['name']}")
    if "age" in kwargs:
        print(f"Age: {kwargs['age']}")
    if "city" in kwargs:
        print(f"City: {kwargs['city']}")
    print("-" * 20)

print_user_info(name="Alice", age=30)
print_user_info(occupation="Engineer", country="USA")
print_user_info() # 也可以不传参数

输出:

kwargs type: <class 'dict'>
kwargs content: {'name': 'Alice', 'age': 30}
Name: Alice
Age: 30
--------------------
kwargs type: <class 'dict'>
kwargs content: {'occupation': 'Engineer', 'country': 'USA'}
--------------------
kwargs type: <class 'dict'>
kwargs content: {}
--------------------

3. 同时使用 *args**kwargs

你可以在同一个函数定义中同时使用 *args**kwargs。在这种情况下,它们必须遵循特定的顺序:普通参数 -> *args -> **kwargs

def describe_item(item_name, *features, **details):
    """
    描述一个物品,包括其名称、任意数量的特征和任意数量的额外细节。
    """
    print(f"Item: {item_name}")
    if features:
        print(f"Features: {features}")
    if details:
        print(f"Details:")
        for key, value in details.items():
            print(f"  {key}: {value}")
    print("-" * 30)

describe_item("Laptop", "lightweight", "fast", manufacturer="Dell", price=1200)
describe_item("Book", "paperback")
describe_item("Bottle")

输出:

Item: Laptop
Features: ('lightweight', 'fast')
Details:
  manufacturer: Dell
  price: 1200
------------------------------
Item: Book
Features: ('paperback',)
------------------------------
Item: Bottle
------------------------------

4. 解包(Unpacking)参数

*** 不仅用于收集参数,还可以用于解包(unpacking) 序列和字典,以便将它们作为参数传递给函数。

  • * 解包可迭代对象:将列表或元组中的元素作为单独的位置参数传递。
  • ** 解包字典:将字典中的键值对作为单独的关键字参数传递。

示例:

def my_function(a, b, c):
    print(f"a: {a}, b: {b}, c: {c}")

# 使用 * 解包列表/元组
my_list = [1, 2, 3]
my_function(*my_list) # 等同于 my_function(1, 2, 3)

my_tuple = (4, 5, 6)
my_function(*my_tuple) # 等同于 my_function(4, 5, 6)

# 使用 ** 解包字典
my_dict = {'a': 7, 'b': 8, 'c': 9}
my_function(**my_dict) # 等同于 my_function(a=7, b=8, c=9)

# 同时解包
def complex_function(x, y, *args, **kwargs):
    print(f"x: {x}, y: {y}")
    print(f"args: {args}")
    print(f"kwargs: {kwargs}")

data_args = [10, 20, 30]
data_kwargs = {'key1': 'value1', 'key2': 'value2'}

complex_function(5, 6, *data_args, **data_kwargs)

输出:

a: 1, b: 2, c: 3
a: 4, b: 5, c: 6
a: 7, b: 8, c: 9
x: 5, y: 6
args: (10, 20, 30)
kwargs: {'key1': 'value1', 'key2': 'value2'}

总结

  • *args: 收集所有额外的位置参数到一个元组中。
  • **kwargs: 收集所有额外的关键字参数到一个字典中。
  • 它们使得函数能够处理不定数量的输入,极大地增强了函数的灵活性和通用性。
  • 它们也可以用于解包可迭代对象(*)和字典(**),将它们的元素作为参数传递给函数。

理解并熟练使用 *args**kwargs 是编写更灵活、更通用的 Python 函数的关键。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容