
一、开篇:当参数数量不确定时
想象你正在写一个日志函数——有时候你需要记录1条信息,有时候是5条。或者你在写一个数学函数,要对任意多个数字求和。如果参数数量是固定的,这类问题就很棘手。
⌨️ 来看:
# 问题:写一个函数,对任意多个数字求和
# 如果用普通参数,只能处理固定数量的数字
def sum_two(a, b):
return a + b
def sum_three(a, b, c):
return a + b + c
def sum_four(a, b, c, d):
return a + b + c + d
# 如果要汇总100个数字呢?不可能写100个参数!
# ✅ python的解决方案:*args
def sum_all(*args):
"""对任意多个数字求和"""
return sum(args)
print(sum_all(1, 2)) # 3
print(sum_all(1, 2, 3, 4, 5)) # 15
print(sum_all(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)) # 550
# 传多少个数字都行!💡 *args 和 **kwargs 是python函数参数系统中最灵活的特性。它们让你写出能接受"任意数量参数"的函数——这是许多高级python模式(装饰器、子类扩展、api封装)的基石。
这篇文章,我们就从零开始,彻底掌握这两个神奇的语法。
二、*args:接收任意数量的位置参数
2.1 *args的基本概念
# *args的语法含义:
# 1. * 是操作符,表示"打包剩余的位置参数"
# 2. args 是约定俗成的名字(你可以用其他名字,但强烈不建议)
# 3. 在函数内部,args 是一个元组(tuple)
# 4. args 包含了所有"多出来的"位置参数
def demo_args(first, *args):
"""演示*args:first是必需的,*args收集剩余参数"""
print(f"第一个参数 first = {first}")
print(f"剩余参数 *args = {args}")
print(f"args的类型: {type(args)}")
print(f"args的元素个数: {len(args)}")
print("---")
demo_args(1)
# 第一个参数 first = 1
# 剩余参数 *args = ()
# args的类型: <class 'tuple'>
# args的元素个数: 0
demo_args(1, 2, 3, 4, 5)
# 第一个参数 first = 1
# 剩余参数 *args = (2, 3, 4, 5)
# args的类型: <class 'tuple'>
# args的元素个数: 4
# 💡 关键理解:*args总是打包成元组,即使只有一个元素
demo_args("a", "b")
# 第一个参数 first = a
# 剩余参数 *args = ('b',) <--- 注意逗号!这是元组2.2 *args的常见使用模式
# 模式一:纯*args函数——所有参数都是可选的
def concatenate(*strings, separator=" "):
"""拼接任意多个字符串"""
if not strings:
return ""
return separator.join(str(s) for s in strings)
print(concatenate()) # ""(空字符串)
print(concatenate("hello")) # "hello"
print(concatenate("hello", "world")) # "hello world"
print(concatenate("a", "b", "c", separator="-")) # "a-b-c"
print(concatenate("python", "is", "awesome", separator=" | ")) # "python | is | awesome"
# 模式二:多个普通参数 + *args
def log_message(level, timestamp, *messages):
"""记录日志:level和timestamp必需,messages可选任意数量"""
for msg in messages:
print(f"[{level}] {timestamp} - {msg}")
if not messages:
print(f"[{level}] {timestamp} - (无消息)")
log_message("info", "2024-06-15", "服务器启动", "端口监听8080", "数据库连接成功")
# [info] 2024-06-15 - 服务器启动
# [info] 2024-06-15 - 端口监听8080
# [info] 2024-06-15 - 数据库连接成功
log_message("warning", "2024-06-15")
# [warning] 2024-06-15 - (无消息)
# 模式三:*args用于转发参数
def wrapper(func, *args):
"""一个简单的函数包装器,转发所有参数"""
print(f"调用 {func.__name__},参数: {args}")
result = func(*args) # *的解包操作(后面会讲)
print(f"结果: {result}")
return result
def add(a, b):
return a + b
def multiply(a, b, c):
return a * b * c
wrapper(add, 3, 5) # 调用 add,参数: (3, 5) → 结果: 8
wrapper(multiply, 2, 3, 4) # 调用 multiply,参数: (2, 3, 4) → 结果: 24
2.3 *args在数据处理中的应用
# 场景一:求任意数量数据的统计值
def calculate_statistics(*values):
"""计算任意数量数值的统计信息"""
if not values:
return none
n = len(values)
total = sum(values)
average = total / n
maximum = max(values)
minimum = min(values)
# 计算方差
variance = sum((x - average) ** 2 for x in values) / n
return {
"count": n,
"sum": total,
"avg": round(average, 2),
"max": maximum,
"min": minimum,
"variance": round(variance, 2),
}
stats = calculate_statistics(85, 92, 78, 90, 88, 95, 82, 87)
print(stats)
# {'count': 8, 'sum': 697, 'avg': 87.12, 'max': 95, 'min': 78, 'variance': 26.86}
# 场景二:批量过滤
def filter_by_multiple_conditions(data, *conditions):
"""根据多个条件函数过滤数据——所有条件都必须满足"""
result = data
for condition in conditions:
result = [item for item in result if condition(item)]
return result
# 过滤出偶数且大于10的数
numbers = list(range(1, 21))
filtered = filter_by_multiple_conditions(
numbers,
lambda x: x % 2 == 0, # 条件1:偶数
lambda x: x > 10, # 条件2:大于10
lambda x: x < 18 # 条件3:小于18
)
print(filtered) # [12, 14, 16]三、**kwargs:接收任意数量的关键字参数
3.1 **kwargs的基本概念
# **kwargs的语法含义:
# 1. ** 是操作符,表示"打包剩余的关键字参数"
# 2. kwargs 是约定俗成的名字(keyword arguments的缩写)
# 3. 在函数内部,kwargs 是一个字典(dict)
# 4. kwargs 的键是参数名(字符串),值是参数值
def demo_kwargs(name, **kwargs):
"""演示**kwargs:name是必需的,**kwargs收集剩余关键字参数"""
print(f"name = {name}")
print(f"kwargs = {kwargs}")
print(f"kwargs的类型: {type(kwargs)}")
print("---")
demo_kwargs("张三")
# name = 张三
# kwargs = {}
# kwargs的类型: <class 'dict'>
demo_kwargs("李四", age=25, city="北京", job="工程师")
# name = 李四
# kwargs = {'age': 25, 'city': '北京', 'job': '工程师'}
# kwargs的类型: <class 'dict'>
# 遍历kwargs
def print_user_info(username, **kwargs):
"""打印用户信息——kwargs包含所有额外信息"""
print(f"用户名: {username}")
print("-" * 30)
for key, value in kwargs.items():
print(f" {key}: {value}")
print("-" * 30)
print_user_info(
"zhangsan",
age=28,
email="zs@test.com",
phone="13800138000",
department="技术部",
title="高级工程师"
)3.2 **kwargs的实际应用
# 场景一:灵活的配置函数
def create_html_element(tag, content, **attributes):
"""创建html元素——**kwargs收集所有html属性"""
# 构建属性字符串
attr_parts = []
for key, value in attributes.items():
# 将python风格的下划线命名转为html风格的连字符命名
html_key = key.replace("_", "-")
attr_parts.append(f'{html_key}="{value}"')
attr_string = " ".join(attr_parts)
if attr_string:
attr_string = " " + attr_string
return f"<{tag}{attr_string}>{content}</{tag}>"
# 使用——属性名和值都是灵活的
print(create_html_element("div", "hello"))
# <div>hello</div>
print(create_html_element("a", "点击这里", href="https://example.com" rel="external nofollow" rel="external nofollow" , target="_blank"))
# <a href="https://example.com" rel="external nofollow" rel="external nofollow" target="_blank">点击这里</a>
print(create_html_element("input", "", type="text", name="username",
placeholder="请输入用户名", class_name="form-input",
data_validate="required"))
# <input type="text" name="username" placeholder="请输入用户名"
# class-name="form-input" data-validate="required"></input>
# 场景二:数据库查询构建器
def build_select_query(table, **conditions):
"""根据条件构建select查询"""
if not conditions:
sql = f"select * from {table}"
else:
where_parts = []
for column, value in conditions.items():
if isinstance(value, str):
where_parts.append(f"{column} = '{value}'")
else:
where_parts.append(f"{column} = {value}")
where_clause = " and ".join(where_parts)
sql = f"select * from {table} where {where_clause}"
return sql
print(build_select_query("users"))
# select * from users
print(build_select_query("users", status="active", age=25))
# select * from users where status = 'active' and age = 25
print(build_select_query("products", category="electronics", price=99, in_stock=true))
# select * from products where category = 'electronics' and price = 99 and in_stock = true
# 场景三:继承时扩展父类方法
class animal:
def __init__(self, name, **kwargs):
self.name = name
# 处理其他可能的关键字参数...
class dog(animal):
def __init__(self, name, breed, **kwargs):
super().__init__(name, **kwargs) # 将额外参数传给父类
self.breed = breed
class servicedog(dog):
def __init__(self, name, breed, service_type, **kwargs):
super().__init__(name, breed, **kwargs)
self.service_type = service_type
# 传递任意额外的参数
dog = servicedog("buddy", "金毛", "导盲犬", age=3, trainer="张三", certified=true)
print(f"名字: {dog.name}, 品种: {dog.breed}, 服务: {dog.service_type}")
# 名字: buddy, 品种: 金毛, 服务: 导盲犬四、*args和**kwargs同时使用
4.1 基本组合
# ⌨️ *args和**kwargs的组合使用
# *args收集多余的位置参数(元组)
# **kwargs收集多余的关键字参数(字典)
def universal_function(*args, **kwargs):
"""万能函数——接受任何形式的参数"""
print(f"位置参数 *args = {args}")
print(f"关键字参数 **kwargs = {kwargs}")
print("---")
# 只传位置参数
universal_function(1, 2, 3)
# 位置参数 *args = (1, 2, 3)
# 关键字参数 **kwargs = {}
# 只传关键字参数
universal_function(name="张三", age=25)
# 位置参数 *args = ()
# 关键字参数 **kwargs = {'name': '张三', 'age': 25}
# 混合传递
universal_function(1, 2, 3, name="李四", city="北京")
# 位置参数 *args = (1, 2, 3)
# 关键字参数 **kwargs = {'name': '李四', 'city': '北京'}
# 甚至可以一个参数都不传
universal_function()
# 位置参数 *args = ()
# 关键字参数 **kwargs = {}4.2 实际应用:万能日志函数
import time
def log(*args, level="info", **kwargs):
"""
万能日志函数
*args: 日志消息内容(一个或多个)
level: 日志级别(可用关键字指定)
**kwargs: 额外的上下文信息
"""
timestamp = time.strftime("%y-%m-%d %h:%m:%s")
# 拼接消息
message = " ".join(str(arg) for arg in args)
# 构建日志行
log_line = f"[{level}] {timestamp} - {message}"
# 附加上下文
if kwargs:
context = ", ".join(f"{k}={v}" for k, v in kwargs.items())
log_line += f" | {context}"
print(log_line)
# 各种调用方式
log("服务器启动") # 简单消息
# [info] 2024-06-15 10:30:00 - 服务器启动
log("用户登录", "用户名: zhangsan") # 多个消息片段
# [info] 2024-06-15 10:30:01 - 用户登录 用户名: zhangsan
log("数据库查询", "耗时过长", level="warning", query="select * from logs", duration_ms=3500)
# [warning] 2024-06-15 10:30:02 - 数据库查询 耗时过长 | query=select * from logs, duration_ms=3500
log("支付失败", level="error", user_id=12345, amount=99.9, reason="余额不足")
# [error] 2024-06-15 10:30:03 - 支付失败 | user_id=12345, amount=99.9, reason=余额不足4.3 实际应用:装饰器的通用写法
# ⌨️ 装饰器必须使用*args和**kwargs来保持通用性
# 因为装饰器不知道被装饰函数接受什么参数
def log_function_call(func):
"""记录函数调用信息的装饰器"""
def wrapper(*args, **kwargs):
print(f"→ 调用 {func.__name__}")
if args:
print(f" 位置参数: {args}")
if kwargs:
print(f" 关键字参数: {kwargs}")
result = func(*args, **kwargs) # 原样传递
print(f"← {func.__name__} 返回: {result}")
return result
return wrapper
@log_function_call
def add(a, b):
return a + b
@log_function_call
def greet(name, greeting="你好"):
return f"{greeting},{name}!"
@log_function_call
def create_user(username, **details):
return {"username": username, **details}
# 测试——不同签名的函数都能正常工作
add(3, 5)
# → 调用 add
# 位置参数: (3, 5)
# ← add 返回: 8
greet("张三", greeting="早上好")
# → 调用 greet
# 位置参数: ('张三',)
# 关键字参数: {'greeting': '早上好'}
# ← greet 返回: 早上好,张三!
create_user("zhangsan", age=25, city="北京", email="zs@test.com")
# → 调用 create_user
# 位置参数: ('zhangsan',)
# 关键字参数: {'age': 25, 'city': '北京', 'email': 'zs@test.com'}
# ← create_user 返回: {'username': 'zhangsan', 'age': 25, 'city': '北京', 'email': 'zs@test.com'}五、* 和 ** 的解包操作
5.1 * 的解包:将序列展开为位置参数
# 💡 * 有两种用法:
# 1. 在函数定义中:*args —— 打包参数
# 2. 在函数调用中:*iterable —— 解包参数
# 回顾:打包
def collect(*args):
print(args)
collect(1, 2, 3) # (1, 2, 3) —— 打包成元组
# 解包:将列表/元组中的元素展开为独立的参数
def multiply(a, b, c):
return a * b * c
# 有一个包含三个数的列表
numbers = [2, 3, 4]
# 不使用解包——很麻烦
result = multiply(numbers[0], numbers[1], numbers[2])
# ✅ 使用*解包——一行搞定
result = multiply(*numbers)
print(f"{numbers} → multiply → {result}") # [2, 3, 4] → multiply → 24
# 💡 *解包适用于任何可迭代对象
my_tuple = (5, 6, 7)
print(multiply(*my_tuple)) # 210
my_string = "abc"
# 字符串也是可迭代的,但这里不太合适
# print(multiply(*my_string)) # 会报错——字符串元素不是数字
# 更实用的例子
def print_table(headers, *rows):
"""打印表格"""
print(" | ".join(str(h) for h in headers))
print("-" * 40)
for row in rows:
print(" | ".join(str(cell) for cell in row))
# 使用解包来传递表格数据
headers = ["姓名", "年龄", "城市"]
data = [
("张三", 25, "北京"),
("李四", 30, "上海"),
("王五", 28, "广州"),
]
print_table(headers, *data) # 将data列表解包为3个独立的位置参数5.2 ** 的解包:将字典展开为关键字参数
# ** 也有两种用法:
# 1. 在函数定义中:**kwargs —— 打包关键字参数
# 2. 在函数调用中:**dict —— 解包字典为关键字参数
def describe_person(name, age, city, job="未知"):
return f"{name}, {age}岁, 来自{city}, 职业{job}"
# 有一个包含参数信息的字典
person_info = {
"name": "张三",
"age": 25,
"city": "北京",
"job": "程序员",
}
# 不使用解包——逐个取出
result1 = describe_person(
person_info["name"],
person_info["age"],
person_info["city"],
person_info["job"]
)
# ✅ 使用**解包——一行搞定
result2 = describe_person(**person_info)
print(result2) # 张三, 25岁, 来自北京, 职业程序员
# 💡 字典的键必须与参数名完全匹配
# person_info = {"name": "张三", "years_old": 25} # 键名不匹配!
# describe_person(**person_info) # typeerror: unexpected keyword argument 'years_old'
# 💡 字典可以包含额外的键——如果函数接受**kwargs
def flexible_function(name, **kwargs):
"""接受name和其他任意关键字参数"""
print(f"name={name}")
print(f"extra={kwargs}")
config = {"name": "test", "debug": true, "timeout": 30, "host": "localhost"}
flexible_function(**config)
# name=test
# extra={'debug': true, 'timeout': 30, 'host': 'localhost'}5.3 * 和 ** 解包的实际场景
# 场景一:合并多个字典来调用函数
default_config = {"debug": false, "timeout": 30, "retries": 3}
user_config = {"debug": true, "timeout": 60} # 用户自定义的配置
def start_server(host, port, debug=false, timeout=30, retries=3):
"""启动服务器"""
config = {
"host": host,
"port": port,
"debug": debug,
"timeout": timeout,
"retries": retries,
}
print(f"启动服务器: {config}")
# 合并默认配置和用户配置
# 后面的会覆盖前面的
merged_config = {**default_config, **user_config}
start_server("localhost", 8080, **merged_config)
# 启动服务器: {'host': 'localhost', 'port': 8080, 'debug': true, 'timeout': 60, 'retries': 3}
# 场景二:动态构建函数调用
def api_call(endpoint, method="get", **params):
"""模拟api调用"""
query_string = "&".join(f"{k}={v}" for k, v in params.items())
url = f"{endpoint}?{query_string}" if query_string else endpoint
print(f"{method} {url}")
# 根据条件动态构建参数
def search_products(category=none, min_price=none, max_price=none, sort_by=none):
"""搜索产品——动态构建api参数"""
params = {}
if category:
params["category"] = category
if min_price is not none:
params["min_price"] = min_price
if max_price is not none:
params["max_price"] = max_price
if sort_by:
params["sort_by"] = sort_by
# 使用**解包来动态传参
api_call("/api/products", **params)
search_products(category="electronics")
# get /api/products?category=electronics
search_products(min_price=100, max_price=500, sort_by="price_asc")
# get /api/products?min_price=100&max_price=500&sort_by=price_asc
search_products(category="books", sort_by="newest")
# get /api/products?category=books&sort_by=newest六、参数定义顺序的完整规则
6.1 标准参数顺序
# ⌨️ python函数参数的完整定义顺序
# 遵循以下顺序(部分是可选的):
# def func(
# positional_only, # 位置专用参数(/之前)
# /, # 位置专用参数分隔符(python 3.8+)
# positional_or_kw, # 普通参数(位置或关键字)
# *args, # 可变位置参数
# kw_only, # 关键字专用参数(*或*args之后)
# **kwargs # 可变关键字参数(必须在最后)
# ):
# 完整示例
def complete_function(a, b, /, c, d, *args, e, f, **kwargs):
"""
a, b : 位置专用参数(只能按位置传)
c, d : 位置或关键字都可以
*args : 额外的位置参数
e, f : 关键字专用参数
**kwargs : 额外的关键字参数
"""
print(f"a={a}, b={b}")
print(f"c={c}, d={d}")
print(f"args={args}")
print(f"e={e}, f={f}")
print(f"kwargs={kwargs}")
# 正确的调用方式
complete_function(1, 2, 3, 4, 5, 6, 7, e=8, f=9, x=10, y=11)
# a=1, b=2
# c=3, d=4
# args=(5, 6, 7)
# e=8, f=9
# kwargs={'x': 10, 'y': 11}
# 💡 最实用的简化版本(日常开发中最常见)
def practical_function(pos1, pos2, *args, kw1="default1", kw2="default2", **kwargs):
"""日常实用的参数组合"""
print(f"必需参数: {pos1}, {pos2}")
print(f"额外的位置参数: {args}")
print(f"关键字参数: {kw1}, {kw2}")
print(f"额外的关键字参数: {kwargs}")
practical_function("a", "b", "c", "d", kw1="custom", extra1=1, extra2=2)
# 必需参数: a, b
# 额外的位置参数: ('c', 'd')
# 关键字参数: custom, default2
# 额外的关键字参数: {'extra1': 1, 'extra2': 2}七、常见陷阱与注意事项
7.1 陷阱一:*args后面的参数必须用关键字
# ⚠️ 定义在*args后面的参数只能用关键字传递
def func(a, *args, b):
"""b在*args后面,只能用关键字传递"""
print(f"a={a}, args={args}, b={b}")
# ✅ 正确
func(1, 2, 3, b=4) # a=1, args=(2, 3), b=4
# ❌ 错误
# func(1, 2, 3, 4)
# typeerror: func() missing 1 required keyword-only argument: 'b'
# python把4也当成*args的一部分了,b没有得到值
# 💡 这就是为什么print()函数的sep和end参数必须用关键字传递
# print(*objects, sep=' ', end='\n', file=none, flush=false)
# sep和end在*objects后面,所以只能用关键字!
print("a", "b", "c", sep="-", end="!")
# a-b-c!7.2 陷阱二:**kwargs的键是字符串
def demo(**kwargs):
"""演示kwargs的键总是字符串"""
for key in kwargs:
print(f"key类型: {type(key)}, key值: {key}")
demo(name="张三", age=25)
# key类型: <class 'str'>, key值: name
# key类型: <class 'str'>, key值: age
# 你不能直接传数字作为键
# demo(**{1: "value"}) # typeerror: keywords must be strings
# ⚠️ 但你可以通过解包来用非字符串键——不过会报错
# 只有字符串键才能用作关键字参数7.3 陷阱三:*args和**kwargs的命名
# 约定俗成但不强制
# args和kwargs只是名字,关键是*和**
# 可以改名(但不推荐)
def example(*arguments, **keyword_arguments):
print(f"arguments={arguments}")
print(f"keyword_arguments={keyword_arguments}")
example(1, 2, 3, name="test")
# arguments=(1, 2, 3)
# keyword_arguments={'name': 'test'}
# ✅ 推荐:始终使用args和kwargs
# 原因:这是python社区的通用约定,任何python程序员一看就懂
# ⚠️ 注意:kwargs常被误写为kwarg(少了s)
# **kwargs √ —— keyword arguments的缩写
# **kwarg × —— 语法上没问题,但破坏了约定八、实战案例
8.1 灵活的数据验证器
def validate( value, *validators, **error_messages):
"""
对值依次应用多个验证器
value: 要验证的值
*validators: 验证函数列表,每个函数接收value返回true/false
**error_messages: 验证失败时的错误消息配置
"""
errors = []
default_message = error_messages.get("default", "验证失败")
for i, validator in enumerate(validators):
try:
if not validator(value):
msg = error_messages.get(
validator.__name__,
f"验证器{i + 1}: {default_message}"
)
errors.append(msg)
except exception as e:
errors.append(f"验证异常: {e}")
if errors:
return {"valid": false, "errors": errors}
return {"valid": true, "errors": []}
# 使用验证器
def is_positive(n):
return n > 0
def is_even(n):
return n % 2 == 0
def is_less_than_100(n):
return n < 100
# 单个验证
result = validate(42, is_positive, is_even, is_less_than_100)
print(result) # {'valid': true, 'errors': []}
# 验证失败时
result = validate(
-5,
is_positive, is_even, is_less_than_100,
is_positive="必须为正数",
is_even="必须为偶数",
default="不符合要求"
)
print(result)
# {'valid': false, 'errors': ['必须为正数', '必须为偶数']}8.2 灵活的api路由装饰器
# 模拟web框架中的路由注册——使用*args和**kwargs
class miniwebframework:
"""微型web框架示例"""
def __init__(self):
self.routes = []
def route(self, path, *methods, **options):
"""
路由注册装饰器
path: 路由路径
*methods: http方法列表(get, post等)
**options: 其他配置(auth_required, rate_limit等)
"""
if not methods:
methods = ("get",) # 默认get方法
def decorator(handler_func):
route_info = {
"path": path,
"methods": methods,
"handler": handler_func,
**options # 合并所有额外配置
}
self.routes.append(route_info)
return handler_func
return decorator
def print_routes(self):
"""打印所有注册的路由"""
print("已注册的路由:")
for route in self.routes:
print(f" {','.join(route['methods'])} {route['path']}")
if route.get('auth_required'):
print(f" 🔒 需要认证")
if route.get('rate_limit'):
print(f" ⏱ 限流: {route['rate_limit']}/分钟")
# 使用框架
app = miniwebframework()
@app.route("/")
def index():
return "首页"
@app.route("/users", "get", "post", auth_required=true)
def users():
return "用户列表"
@app.route("/admin", "get", "post", "delete",
auth_required=true, rate_limit=10)
def admin():
return "管理页面"
@app.route("/api/data", "get", rate_limit=60)
def api_data():
return "api数据"
app.print_routes()
# 已注册的路由:
# get /
# get,post /users
# 🔒 需要认证
# get,post,delete /admin
# 🔒 需要认证
# ⏱ 限流: 10/分钟
# get /api/data
# ⏱ 限流: 60/分钟九、总结
*args 和 **kwargs 是python函数参数系统中最灵活的部分。它们让你写出能适应各种调用方式的通用函数。
💡 核心要点回顾:
| 特性 | 定义 | 调用时解包 | 内部类型 |
|---|---|---|---|
*args | 打包多余位置参数 | *list 展开列表 | tuple |
**kwargs | 打包多余关键字参数 | **dict 展开字典 | dict |
✅ 什么时候用:
- 装饰器:必须使用
*args和**kwargs来保证通用性 - 子类/父类协作:
super().__init__(*args, **kwargs)转发参数 - api封装:将参数透传给底层函数
- 配置函数:接受任意数量的可选配置项
- 日志/调试函数:灵活接受各种信息
⚠️ 注意事项:
*args后面的参数只能用关键字传递**kwargs的键必须是字符串- 过度使用会降低代码可读性——在灵活性和明确性之间找平衡
- 不要滥用
*args, **kwargs作为偷懒的手段——如果函数只有3个确定参数,就直接写出来
掌握了*args和**kwargs,你就拥有了python函数编程中最大的灵活性。在下一篇文章中,我们将系统学习参数传递顺序的强制规则——把这些散落的知识点串成一条完整的线。
到此这篇关于python函数可变参数*args与**kwargs全解析的文章就介绍到这了,更多相关python可变参数*args与**kwargs内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论