跳到内容

重新实现的运算符 (FURB118)

派生自 refurb 代码检查工具。

有时提供修复。

此规则不稳定且处于预览状态。使用需要 --preview 标志。

作用

检查可以被 operator 模块中的函数替换的 lambda 表达式和函数定义。

为什么这不好?

operator 模块提供了实现与相应运算符相同功能的函数。例如,operator.add 通常等同于 lambda x, y: x + y。使用 operator 模块中的函数更简洁,并且更清晰地表达了代码的意图。

示例

import functools

nums = [1, 2, 3]
total = functools.reduce(lambda x, y: x + y, nums)

建议改为

import functools
import operator

nums = [1, 2, 3]
total = functools.reduce(operator.add, nums)

修复安全性

此规则提供的修复程序始终标记为不安全。虽然修复程序所做的更改很少会破坏您的代码,但 operator 模块中的函数与用户定义的函数之间存在两种差异。对于 Ruff 来说,要检测这些差异是否会在 Ruff 为此规则发出诊断的具体情况下有所影响,这将是非常困难的。

第一个区别是 operator 函数不能使用关键字参数调用,但大多数用户定义的函数可以。如果将 add 函数定义为 add = lambda x, y: x + y,则用 operator.add 替换此函数将导致稍后的调用引发 TypeError,如果稍后使用关键字参数调用该函数,例如 add(x=1, y=2)

第二个区别是用户定义的函数是 描述符,但 operator 模块中定义的函数并非如此。实际上,这意味着在类体中定义函数(无论是使用 def 语句还是将 lambda 函数分配给变量)是在该类上定义实例方法的有效方法;在类创建后将用户定义的函数 monkeypatch 到类上也会产生相同的效果。对于 operator 函数来说,情况并非如此:将 operator 函数分配给类体中的变量或将一个函数 monkeypatch 到类上不会创建有效的实例方法。 Ruff 将避免在此规则中对类体中的函数定义发出诊断;但是,它目前没有足够复杂的类型推断来避免发出此诊断,如果用户定义的函数在类构造后被 monkeypatch 到类上。