第34集:函数参数——关键字参数

学习目标

  • 理解关键字参数的概念
  • 掌握关键字参数的使用方法
  • 学会混合使用位置参数和关键字参数
  • 了解关键字参数的优势

一、什么是关键字参数?

关键字参数是在调用函数时,通过参数名来传递参数的方式。

核心特点

  • 不依赖顺序:可以按任意顺序传递参数
  • 代码清晰:明确指出每个值的含义
  • 易于维护:修改参数顺序不影响调用
  • 可选跳过:对于有默认值的参数,可以跳过不传

生活类比

  • 点餐时说"我要咖啡,不要糖":明确指定选项
  • 关键字参数就像"指定选项"的方式,而不是按顺序选择

二、关键字参数的语法

调用语法

函数名(参数1=值1, 参数2=值2, ...)

与位置参数对比

调用方式 示例 说明
位置参数 func(1, 2, 3) 按顺序传递
关键字参数 func(a=1, b=2, c=3) 按名称传递

三、基础示例

示例1:基本关键字参数

def introduce(name, age, city):
    """自我介绍"""
    print(f"我叫{name},今年{age}岁,来自{city}")

# 使用关键字参数调用
introduce(name="小明", age=25, city="北京")
# 输出:我叫小明,今年25岁,来自北京

# 顺序可以改变
introduce(city="上海", name="小红", age=22)
# 输出:我叫小红,今年22岁,来自上海

示例2:部分使用关键字参数

def greet(greeting, name, message):
    """打招呼"""
    print(f"{greeting},{name}!{message}")

# 前两个用位置,最后一个用关键字
greet("你好", "小明", message="欢迎学习Python")
# 输出:你好,小明!欢迎学习Python

# 第一个用位置,后两个用关键字
greet("早上好", name="小红", message="今天天气不错")
# 输出:早上好,小红!今天天气不错

示例3:混合使用位置参数和关键字参数

def calculate(price, quantity, discount, tax):
    """计算总价"""
    subtotal = price * quantity
    after_discount = subtotal * (1 - discount)
    total = after_discount * (1 + tax)
    return total

# 完全使用关键字参数
result1 = calculate(price=100, quantity=2, discount=0.1, tax=0.1)
print(f"总价1:{result1}")

# 部分使用关键字参数
result2 = calculate(100, 2, discount=0.1, tax=0.1)
print(f"总价2:{result2}")

四、关键字参数的规则

规则1:位置参数必须在关键字参数之前

def func(a, b, c):
    pass

# ✅ 正确:位置参数在前,关键字参数在后
func(1, 2, c=3)

# ❌ 错误:关键字参数不能在位置参数之前
# func(a=1, 2, 3)  # 报错

规则2:每个参数只能传递一次

def func(a, b, c):
    pass

# ❌ 错误:参数b被传递了两次
# func(1, b=2, c=3)  # 报错:b被重复赋值

规则3:不能传递不存在的参数名

def func(a, b, c):
    pass

# ❌ 错误:参数d不存在
# func(1, 2, d=3)  # 报错

五、关键字参数的应用

示例4:配置函数

def configure_server(host, port, timeout, ssl_enabled, max_connections):
    """配置服务器"""
    print(f"主机:{host}")
    print(f"端口:{port}")
    print(f"超时:{timeout}秒")
    print(f"SSL:{'启用' if ssl_enabled else '禁用'}")
    print(f"最大连接数:{max_connections}")

# 使用关键字参数,顺序任意
configure_server(
    port=8080,
    ssl_enabled=True,
    host="localhost",
    max_connections=100,
    timeout=30
)

示例5:数据库连接

def connect_database(host, port, database, username, password, timeout):
    """连接数据库"""
    print(f"连接数据库:")
    print(f"  主机:{host}")
    print(f"  端口:{port}")
    print(f"  数据库:{database}")
    print(f"  用户名:{username}")
    print(f"  密码:{'*' * len(password)}")
    print(f"  超时:{timeout}秒")

# 使用关键字参数,清晰明了
connect_database(
    database="mydb",
    host="192.168.1.100",
    password="secret",
    username="admin",
    port=5432,
    timeout=10
)

示例6:发送消息

def send_message(to, from_user, subject, body, priority="normal", cc=None):
    """发送消息"""
    print(f"\n发送消息:")
    print(f"  收件人:{to}")
    print(f"  发件人:{from_user}")
    print(f"  主题:{subject}")
    print(f"  内容:{body[:30]}...")
    print(f"  优先级:{priority}")
    if cc:
        print(f"  抄送:{cc}")

# 使用关键字参数
send_message(
    to="user@example.com",
    from_user="admin@example.com",
    subject="测试消息",
    body="这是一条测试消息的内容",
    priority="high"
)

六、默认参数与关键字参数配合

示例7:灵活的函数调用

def create_user(username, email, role="user", active=True, profile=None):
    """创建用户"""
    user = {
        "username": username,
        "email": email,
        "role": role,
        "active": active,
        "profile": profile
    }
    return user

# 使用默认值
user1 = create_user("user1", "user1@example.com")
print(f"用户1:{user1}")

# 修改部分默认值
user2 = create_user(
    username="admin",
    email="admin@example.com",
    role="administrator",
    active=True
)
print(f"用户2:{user2}")

# 指定所有参数
user3 = create_user(
    username="guest",
    email="guest@example.com",
    role="guest",
    active=False,
    profile="访客账户"
)
print(f"用户3:{user3}")

示例8:文件操作

def save_file(filename, content, mode="w", encoding="utf-8", backup=False):
    """保存文件"""
    print(f"\n保存文件:")
    print(f"  文件名:{filename}")
    print(f"  模式:{mode}")
    print(f"  编码:{encoding}")
    print(f"  备份:{'是' if backup else '否'}")
    print(f"  内容:{content[:30]}...")

# 不同方式的保存
save_file(
    filename="test.txt",
    content="这是文件内容",
    encoding="utf-8",
    mode="w"
)

save_file(
    filename="data.json",
    content='{"key": "value"}',
    mode="w",
    encoding="utf-8",
    backup=True
)

七、关键字参数的优势

优势1:代码更易读

# 位置参数(难以理解)
# func(10, 20, 30, 40, 50)

# 关键字参数(清晰明了)
func(
    width=10,
    height=20,
    depth=30,
    weight=40,
    volume=50
)

优势2:修改参数顺序不影响

def send_email(to, cc, bcc, subject, body):
    """发送邮件"""
    print(f"发送给:{to}")

# 可以随意调整参数顺序
send_email(
    body="内容",
    subject="主题",
    bcc="密送@example.com",
    cc="抄送@example.com",
    to="收件人@example.com"
)

优势3:可以跳过某些参数

def process_data(data, sort=False, filter=None, transform=None, output="print"):
    """处理数据"""
    print(f"数据:{data}")
    if sort:
        print("排序数据")
    if filter:
        print(f"过滤:{filter}")
    if transform:
        print(f"转换:{transform}")
    print(f"输出方式:{output}")

# 只指定需要的参数
process_data([3, 1, 4, 1, 5], sort=True, output="file")

# 跳过不需要的参数
process_data([1, 2, 3], filter="even", transform="double")

八、实际应用案例

案例1:电商平台订单

def create_order(product_id, quantity, price, discount=0, shipping="standard", 
                gift_wrap=False, note="", customer_id=None):
    """创建订单"""
    total = quantity * price * (1 - discount)
    
    print(f"\n订单创建:")
    print(f"  产品ID:{product_id}")
    print(f"  数量:{quantity}")
    print(f"  单价:¥{price}")
    print(f"  折扣:{discount*100}%")
    print(f"  总价:¥{total:.2f}")
    print(f"  配送:{shipping}")
    print(f"  礼品包装:{'是' if gift_wrap else '否'}")
    if note:
        print(f"  备注:{note}")
    if customer_id:
        print(f"  客户ID:{customer_id}")

# 创建不同类型的订单
create_order(
    product_id="P001",
    quantity=2,
    price=99.99
)

create_order(
    product_id="P002",
    quantity=1,
    price=299.99,
    discount=0.1,
    shipping="express",
    gift_wrap=True,
    note="生日礼物",
    customer_id="C12345"
)

案例2:图表配置

def draw_chart(title, data, type="bar", color="blue", show_legend=True, 
               grid=True, width=800, height=600):
    """绘制图表"""
    print(f"\n绘制图表:")
    print(f"  标题:{title}")
    print(f"  数据:{data}")
    print(f"  类型:{type}")
    print(f"  颜色:{color}")
    print(f"  显示图例:{'是' if show_legend else '否'}")
    print(f"  显示网格:{'是' if grid else '否'}")
    print(f"  宽度:{width}px")
    print(f"  高度:{height}px")

# 绘制不同样式的图表
draw_chart(
    title="2024年销售额",
    data=[100, 200, 150, 300],
    type="line",
    color="green"
)

draw_chart(
    title="用户分布",
    data=[50, 30, 20],
    type="pie",
    color=["red", "green", "blue"],
    show_legend=True,
    grid=False,
    width=600,
    height=400
)

九、常见错误与调试

错误1:关键字参数在位置参数之前

# ❌ 错误
func(a=1, 2, 3)  # 报错

# ✅ 正确
func(1, 2, c=3)

错误2:参数名拼写错误

def func(a, b, c):
    pass

# ❌ 错误:参数名拼写错误
# func(1, 2, d=3)  # 报错

# ✅ 正确
func(1, 2, c=3)

调试技巧:打印参数

def debug_func(a, b, c):
    """带调试信息的函数"""
    print(f"调试信息:")
    print(f"  a = {a}")
    print(f"  b = {b}")
    print(f"  c = {c}")
    return a + b + c

# 调用函数
debug_func(1, b=2, c=3)

十、关键字参数与位置参数的选择

何时使用位置参数

  • 参数数量少(1-2个)
  • 参数顺序自然明显
  • 追求简洁
  • 参数含义不言自明
# 适合用位置参数
add(10, 20)
max(5, 8, 3)

何时使用关键字参数

  • 参数数量多(3个以上)
  • 参数顺序不明显
  • 需要跳过某些默认参数
  • 代码可读性更重要
# 适合用关键字参数
connect_database(
    host="localhost",
    port=5432,
    database="mydb",
    username="admin",
    password="secret"
)

十一、小结

知识点 说明
关键字参数 通过参数名传递参数
顺序无关 可以按任意顺序传递
代码清晰 明确指出每个值的含义
位置在前 位置参数必须在关键字参数之前
配合默认值 可以只修改需要的参数

十二、课后练习

练习1

定义函数register_user(username, email, age, city),使用关键字参数调用。

练习2

定义函数calculate_rectangle(length, width, unit="cm"),计算矩形面积,支持指定单位。

练习3

定义函数send_sms(to, message, priority="normal", sender=None),发送短信。

练习4

定义函数build_house(length, width, height, floors=1, garden=False),创建房屋信息。

练习5

定义函数config_monitor(brightness, contrast, saturation, volume),配置显示器,使用关键字参数调用。

« 上一篇 函数参数-默认参数 下一篇 » 函数参数-可变参数