Pendulum 的 + 号为何成了 Python 最诡异的运算符?

Why Pendulum had to write the most cursed "+" operator in all of Python

Pendulum 是 Python 中处理日期的流行库,但它的 + 运算符却有个诡异之处:它会根据调用栈中的函数名来决定计算逻辑。这种设计源于它在“时区感知算术”和“无缝替换标准库”之间的两难选择。为了兼容标准库的 astimezone 方法,Pendulum 被迫在运行时检查调用者,导致性能暴跌 600 倍。作者指出,虽然这种猜测机制能暂时解决问题,但本质上是一种脆弱的妥协。最终,通过修改 astimezone 实现来绕过这一陷阱,才是更优解。文章还提醒开发者,在使用 Pendulum 时需注意第三方时区转换、PyPy 环境以及热循环中的性能问题。

Pendulum 被困在进退两难的境地:它无法修改转换逻辑,无法移除 + 运算符的重载,也无法停止作为子类存在。
  1. shoo

    嗯。基于调用栈的内省来改变控制流,这招确实有点损。

    我记得在某个项目里,我们曾巧妙地利用调用栈内省——不是为了改变控制流,而是为了改进日志。在 open_db_connection 工具函数内部,我们自动生成一个描述性名称,说明是哪个代码部分打开了连接:

    例如:some_backend_process: main -> ... > grandparent -> parent -> open_db_connection

    我们会利用调用栈中的信息生成一个字符串(如 "some_backend_process grandparent.parent"),描述调用位置,并在建立连接时将其作为 application_name [1] 传给 postgres。这样一来,如果在运行时遇到有问题的查询,从数据库侧就能获得更多线索,帮我们定位是后端代码库的哪一部分出了问题 [2]。

    当然,也有办法在不窥探调用栈的情况下实现类似效果,比如要求调用者显式传递一个描述性且唯一的名称。但这会让事情更容易出错,尤其是一些开发者喜欢复制粘贴现有的代码块,然后在各处复用同一个名称。

  2. ariebovenberg

    作者在此。我在对比 Pendulum 和我维护的 datetime 库 `whenever` 时遇到了这个问题。我提交了一个移除该 hack 的补丁,但这篇文章讲的是为什么底层设计无法用同样的方式修补。欢迎提问。

  3. reagle

    我盼着 `whenever` 1.0 已经好几年了。看起来现在终于快发布了!

同日更多故事

2026-10-07