Python取余用%运算符还是divmod函数?

夏知夏
夏知夏
发布时间:2026-11-02| 8人浏览过
原创

在Python中求余数时,应该选择%运算符还是divmod()内置函数?本文详细对比两者的运作原理、计算机制、性能差异以及适用场景,帮助读者根据实际需求做出恰当的语法选择。

在 Python 中获取除法余数时,选用 % 运算符还是 divmod() 函数,取决于你的计算目标是仅需要余数,还是需要同时使用商和余数。如果程序只关注余数本身(例如判断奇偶、轮播索引循环),直接使用 % 运算符在语法上最简明,执行速度也最快;如果业务逻辑中既要用到整除后的商、又要用到余数(例如时分秒换算、分页计算、进制转换),使用内置函数 divmod() 能在一次底层操作中返回包含商和余数的二元元组,既能避免重复除法计算,又能让代码意图更加清晰。

一、% 运算符的计算机制与适用场景

% 是 Python 提供的取模运算符。当执行表达式 r = a % b 时,Python 内部遵循向负无穷整除(Floor Division)的数学定义:

# Python 取模公式
r = a - (a // b) * b

由于 a // b 始终向下舍入到最接近的负无穷整数,这也决定了 Python 中余数 r 的符号始终与除数 b 的符号保持一致,而与被除数 a 的正负无关。这一特性不同于 C 或 Java 中直接截断小数部分的取余方式。

在绝大多数仅关注剩余周期的场景中,% 运算符是标准解法。常见用法包括:

  • 奇偶性或倍数判断:检查 n % 2 == 0 或 n % 5 == 0。
  • 环形数组与循环索引:当游标递增越界时,通过 (current_index + 1) % length 将索引限定在有效范围之内。
  • 数据哈希分桶:将计算出的哈希整数按桶容量取模,均匀分散到指定存储槽中。
# 示例:仅使用 % 运算符控制环形队列游标
buffer_size = 5
pointer = 0

for step in range(8):
    pointer = (pointer + 1) % buffer_size
    print(f"步数 {step + 1}: 游标指向索引 {pointer}")
Python取余用%运算符还是divmod函数?
图1:% 运算符基于向负无穷取整原则的推导流程与正负符号归纳

二、divmod() 函数的运作机制与适用场景

divmod(a, b) 是 Python 的内置函数。它接收两个数值参数,并直接返回一个形如 (quotient, remainder) 的元组。在数学逻辑上,它严格等价于:

# divmod 的返回值结构
divmod(a, b) == (a // b, a % b)

尽管数学结果与分别书写 // 和 % 一致,但在底层实现上,现代 CPU 的整数除法硬件指令(例如 x86 架构的 IDIV)在执行一次除法周期时,通常会同时在寄存器中产出商与余数。CPython 虚拟机的整数对象在实现 nb_divmod 槽位时,能够利用这一特性直接完成两者计算,省去二次除法开销。

当需要将一个累积数值递归或级联拆解为不同度量单位时,divmod() 的代码表现力极强。典型场景包括:

  • 时间换算:将总秒数拆解为“时、分、秒”结构。
  • 分页与定位:已知数据列表的绝对索引,求其所在页码及页内第几项。
  • 非十进制数转换:在手写进制转换(如将十进制数转为二进制或十六进制字符串)时,循环提取余数作为当前位,并将商传递至下一轮。
# 示例:使用 divmod() 进行秒数分解
total_seconds = 7520

# 一步提取小时与剩余秒数
hours, remainder = divmod(total_seconds, 3600)
# 再将剩余秒数拆解为分钟与秒
minutes, seconds = divmod(remainder, 60)

print(f"{total_seconds} 秒等于 {hours} 小时 {minutes} 分钟 {seconds} 秒")
# 输出:7520 秒等于 2 小时 5 分钟 20 秒
Python取余用%运算符还是divmod函数?
图2:divmod() 在多级单位分解中的传递过程及输出映射

三、核心差异对比:性能、可读性与开销

在技术选型时,很多开发者容易走入两个极端:要么在任何地方都只写 %,哪怕后面立即再写一行 //;要么误以为 divmod() 总是更高级,即使只要余数也写成 _, r = divmod(a, b)。为了明确两者差异,我们可以从底层执行机制切入分析:

对比维度 % 运算符 divmod(a, b) 函数
返回内容 单一数值(仅余数 r) 二元元组 (q, r)
对应 Python 字节码 BINARY_MODULO(原生指令) LOAD_NAME / CALL_FUNCTION
内存分配开销 无额外容器分配,直接返回整数 需要创建并打包一个 tuple 实例
单项取余耗时 极快(单条指令周期) 稍慢(存在函数调用与元组创建开销)
同时取商与余耗时 若写成 a//b 与 a%b 需进行两次除法 更快,底层仅进行一次除法周期

如果只做单纯的取余判断(例如判断 x % 2 == 0),使用 % 运算符几乎没有多余开销,虚拟机直接执行 BINARY_MODULO 字节码。而如果此时调用 divmod(x, 2),虚拟机需要先查找 divmod 全局函数名、建立函数调用栈帧、在底层构建元组、最后再由上层代码解包并丢弃商。这种做法不仅使代码变得冗长,还凭空增加了大约 2 至 3 倍的调用耗时。

反之,如果在业务中必须同时获得商与余数,分别执行 q = a // b 和 r = a % b 意味着 Python 解释器要先后调用两次除法例程。此时 q, r = divmod(a, b) 凭借单次硬件除法结合,整体耗时比两次独立操作更少,且完全杜绝了变量名写错或除数不一致的潜在隐患。

Python取余用%运算符还是divmod函数?
图3:% 运算符与 divmod() 在字节码调用层级与数据产出机制上的差异

四、常见开发误区与边界细节

1. 浮点数的取模行为与精度限制

无论是 % 还是 divmod(),Python 均支持浮点数运算。例如:

# 浮点数取模示例
print(8.5 % 2.5)          # 输出 1.0
print(divmod(8.5, 2.5))   # 输出 (3.0, 1.0)

但需要注意的是,IEEE 754 浮点数存在二进制表示误差。例如在计算 5.5 % 1.1 时,由于 1.1 无法精确表示为有限位二进制小数,实际输出可能为 1.0999999999999996 而非整齐的 0.0。如果在对精度有严苛要求的科学计算或金融核算中对浮点数求模,应考虑使用 decimal.Decimal 或 Python 标准库中的 math.fmod() 函数。

2. 避免盲目使用下划线丢弃返回值

在部分代码库中,常能见到类似以下的书写习惯:

# 不推荐:仅仅为了取余数而强行调用 divmod
_, rem = divmod(item_id, 10)

# 推荐:清晰直观且执行代价最低
rem = item_id % 10

通过下划线变量 _ 忽略商看似无害,但它强行触发了解释器的函数调度与元组分配。只要不需要商,就应当坚定地使用 % 运算符。

避坑备忘:求余运算中被除数或除数为 0 时的表现——当除数为 0 时,a % 0 和 divmod(a, 0) 均会立即抛出 ZeroDivisionError 异常。在编写动态除法逻辑时,务必先对除数进行非零前置校验。

五、总结:快速选型指南

在面对实际开发需求时,不需要在两者之间过度纠结,可以依据以下规则迅速定夺:

  1. 只取余数:统一使用 % 运算符。语法简洁自然,具备最佳的执行性能与可读性。
  2. 只求整商:统一使用 // 运算符。
  3. 同时需要商和余数:果断使用 q, r = divmod(a, b)。避免先后书写两次除法,让多级换算与分页代码更加稳健、优雅。
Python取余用%运算符还是divmod函数?
图4:针对不同业务场景的除法与取余语法选型总结
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。