飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

位置参数与关键字参数

调用函数时,Python 提供了两种传参方式:位置参数按顺序匹配,关键字参数按名称匹配。两种方式可以混用,但必须遵守严格的顺序规则。

位置传参

位置参数是最直观的传参方式:实参按出现顺序依次绑定到形参:

def describe_pet(animal, name, age):
    return f"{name} 是一只 {age} 岁的 {animal}"

print(describe_pet("狗", "旺财", 3))
# 旺财 是一只 3 岁的 狗

位置传参要求调用者记住参数顺序。顺序错误会导致逻辑错误,且不会报错:

# 顺序写反了,但语法完全合法
print(describe_pet(3, "狗", "旺财"))
# 狗 是一只 旺财 岁的 3   —— 语义荒谬

关键字传参

关键字参数通过 name=value 的形式显式指定形参,不依赖顺序:

print(describe_pet(animal="狗", name="旺财", age=3))
print(describe_pet(age=3, animal="狗", name="旺财"))  # 顺序任意

关键字参数让代码自文档化,调用者无需查看函数定义就能理解每个值的含义。对于参数较多的函数,强烈建议使用关键字参数。

混合使用与顺序规则

位置参数和关键字参数可以混用,但位置参数必须排在关键字参数之前。这是 Python 的硬性语法规则:

# 合法:位置在前,关键字在后
describe_pet("狗", name="旺财", age=3)
describe_pet("狗", "旺财", age=3)

# 非法:关键字参数后接位置参数
# describe_pet(animal="狗", "旺财", 3)
# SyntaxError: positional argument follows keyword argument

这个规则的存在是因为解析器需要明确每个实参对应哪个形参。一旦开始用关键字传参,后续所有参数都必须用关键字,否则解析器无法判断位置实参应该跳过哪些已赋值的形参。

重复赋值错误

不能对同一个形参同时用位置和关键字传参:

def set_point(x, y):
    return (x, y)

# set_point(1, x=2)
# TypeError: set_point() got multiple values for argument 'x'

这里 1 按位置绑定给 x,然后 x=2 试图再次给 x 赋值,Python 拒绝这种歧义。

关键字参数与可读性

当函数有多个布尔标志或数值参数时,关键字参数能极大提升可读性:

def send_email(to, subject, body, cc=None, bcc=None, urgent=False):
    pass

# 不用关键字,很难看懂第三个 False 是什么意思
# send_email("boss@example.com", "周报", "请查收", None, None, False)

# 用关键字,一目了然
send_email(
    to="boss@example.com",
    subject="周报",
    body="请查收",
    urgent=False
)

强制关键字参数的技巧

在定义函数时,可以在参数列表中放一个孤立的 *(不是 *args),其后的所有参数都必须用关键字传递:

def safe_divide(a, b, *, precision=2):
    result = a / b
    return round(result, precision)

print(safe_divide(10, 3, precision=4))  # 合法
# safe_divide(10, 3, 4)               # 非法!precision 必须关键字传参
# TypeError: safe_divide() takes 2 positional arguments but 3 were given

这种写法在 API 设计中非常有用:它防止调用者因多传一个位置参数而意外改变语义。

位置参数与可变参数的交互

当函数定义包含 *args 时,*args 之前的参数可以按位置或关键字传递(除非有 / 限制),*args 收集多余的位置参数。*args 之后的参数则必须用关键字:

def log_message(level, *args, timestamp=None):
    msg = " ".join(str(a) for a in args)
    if timestamp:
        return f"[{timestamp}] {level}: {msg}"
    return f"{level}: {msg}"

print(log_message("INFO", "用户", "登录", timestamp="2024-01-01"))
# [2024-01-01] INFO: 用户 登录

常见错误

关键字参数放错位置:

def demo(a, b, c):
    pass

# demo(a=1, 2, 3)       # SyntaxError
# demo(1, b=2, 3)       # SyntaxError

拼错关键字参数名:

# demo(a=1, bb=2, c=3)  # TypeError: demo() got an unexpected keyword argument 'bb'

遗漏必需参数:

# demo(1)               # TypeError: demo() missing 1 required positional argument: 'c'
# demo(a=1, c=3)        # TypeError: demo() missing 1 required positional argument: 'b'

小结

位置参数依赖顺序,关键字参数依赖名称。混用时位置参数必须在前。关键字参数提升可读性,配合 * 可强制要求关键字传参。掌握这两种方式及其规则,是写出清晰、健壮函数调用的基础。

上一页
定义函数
下一页
默认参数