← 返回题目列表

Python 的 operator 模块有什么用?itemgetter、attrgetter 怎么用?

中等 第 20 / 21 题 更新于 2026/07/31
Pythonoperatoritemgetterattrgetter

简化版

**operator 模块把 Python 的「运算符」和「取值操作」封装成了「函数」——这样运算符也能像函数一样被传递、当作 key/回调使用,比写 lambda 更简洁、更快、更明确。**最常用的三个「取值工厂」:① itemgetter(k)——返回一个函数,取 obj[k](按下标/键取值),itemgetter(1)lambda x: x[1],还能一次取多个 itemgetter(0, 2) 返回元组;② attrgetter('name')——取 obj.name(按属性取),支持嵌套 attrgetter('a.b');③ methodcaller('m', args)——调用 obj.m(args)(调方法),methodcaller('upper')lambda x: x.upper()最典型用途是排序/分组的 keysorted(people, key=attrgetter('age'))sorted(data, key=itemgetter(1)) 比 lambda 更快更清晰。此外operator.add/mul/lt 等把 +/*/< 变成函数(reduce(operator.mul, nums)operator.itemgetter 配合 sorted/max/groupby)。核心记忆:operator 把运算符和取值变函数;itemgetter 取下标/键、attrgetter 取属性、methodcaller 调方法,做 sorted/max/groupby 的 key 比 lambda 快且清晰。

详细版

operator 模块的常用工具

工具作用等价 lambda
itemgetter(1)x[1]lambda x: x[1]
itemgetter(0, 2)取多个 → 元组lambda x: (x[0], x[2])
attrgetter('age')x.agelambda x: x.age
attrgetter('a.b')嵌套属性lambda x: x.a.b
methodcaller('upper')x.upper()lambda x: x.upper()
operator.adda + blambda a,b: a+b
operator.lta < blambda a,b: a<b
from operator import itemgetter, attrgetter, methodcaller
import operator

# itemgetter:按下标/键取值(排序最常用)
data = [("Tom", 25), ("Amy", 30), ("Bob", 20)]
sorted(data, key=itemgetter(1))          # 按年龄 → [('Bob',20),('Tom',25),('Amy',30)]
sorted(data, key=itemgetter(0))          # 按名字

# 取多个(返回元组,多级排序)
rows = [{"name": "a", "age": 25, "score": 90}, ...]
sorted(rows, key=itemgetter("age", "score"))   # 先按 age 再按 score

# attrgetter:按属性取值
class Person:
    def __init__(self, name, age): self.name, self.age = name, age
people = [Person("Tom", 25), Person("Amy", 30)]
sorted(people, key=attrgetter("age"))    # 按 age 排序
attrgetter("name.upper")                 # 嵌套:x.name.upper(属性链)

# methodcaller:调用方法
words = ["Hello", "WORLD", "PyThon"]
sorted(words, key=methodcaller("lower")) # 按小写排序
list(map(methodcaller("strip"), lines))  # 每行 strip

# operator 里的运算符函数
from functools import reduce
reduce(operator.mul, [1,2,3,4])          # 连乘 = 24(比 lambda a,b:a*b 清晰)
reduce(operator.add, [1,2,3])            # 求和(虽然用 sum 更好)

# 配合 groupby(必须先排序)
from itertools import groupby
data = sorted(data, key=itemgetter(1))
for key, group in groupby(data, key=itemgetter(1)):
    print(key, list(group))

⚠️ 核心价值:operator 模块让你「把运算符/取值操作当函数传递」——排序、分组、归约这些需要传「key 函数」或「二元函数」的地方,用 itemgetter/attrgetter/methodcaller 代替 lambda,既更快(C 实现、无 Python 函数调用开销)又更明确(一眼看出是「取第 1 项」还是「取 age 属性」)。三个 getter 的分工很清晰:下标/键用 itemgetterx[k])、属性用 attrgetterx.attr)、方法用 methodcallerx.m()。它们在 sortedmaxmingroupbymap 的 key/函数参数里最常见。itemgetterattrgetter 还支持「一次取多个」——itemgetter(0, 2) 返回 (x[0], x[2]) 元组,正好用于「多级排序」(sorted(data, key=itemgetter("dept", "salary")) 先按部门再按薪资)。至于 operator.add/mul/lt 这些「运算符函数」,主要在需要「把运算符当函数传」的场景用(reduce(operator.mul, ...)sorted(key=...) 里的比较),但求和、极值这些有专门内置(summax)时优先用内置。

完整版教学

一、operator 模块是什么

先理解 operator 的定位:

operator 模块:把"运算符和取值操作"封装成"函数"
  Python 的 +、[]、.、方法调用 → 对应的函数

为什么需要:
  很多场景要传"函数"(key、回调、reduce 的二元函数)
  但运算符/取值不是函数,不能直接传:
    sorted(data, key=???)   # 想按 x[1] 排序
    reduce(???, nums)       # 想用 * 连乘
  → 要么写 lambda,要么用 operator 提供的现成函数

两类内容:
  ① 取值工厂(最常用):
     itemgetter(k)   → 函数:取 x[k]
     attrgetter(a)   → 函数:取 x.a
     methodcaller(m) → 函数:调 x.m()
  ② 运算符函数:
     operator.add(a,b) = a+b
     operator.mul、sub、truediv、mod、pow
     operator.lt/le/gt/ge/eq/ne(比较)
     operator.and_/or_/not_(逻辑/位)
     operator.getitem/setitem/contains

vs lambda:
  itemgetter(1) 代替 lambda x: x[1]
  → 更快(C 实现)、更明确、可读

所以 operator 把运算符/取值封装成函数,用于要传函数的场景(key/reduce),比 lambda 快

operator 模块:把「运算符和取值操作」封装成「函数」(Python 的 +[].、方法调用 → 对应的函数)。为什么需要:很多场景要传「函数」(key、回调、reduce 的二元函数)、但运算符/取值不是函数不能直接传(sorted(data, key=???) 想按 x[1] 排序),要么写 lambda 要么用 operator 的现成函数。两类内容① 取值工厂(最常用)itemgetter(k)(取 x[k])、attrgetter(a)(取 x.a)、methodcaller(m)(调 x.m());② 运算符函数operator.add/mul/sublt/le/gt/eq(比较)、and_/or_getitem/setitem/containsvs lambdaitemgetter(1) 代替 lambda x: x[1](更快、更明确、可读)。理解「operator 把运算符/取值封装成函数;用于要传函数的场景(key/reduce);两类:取值工厂(itemgetter/attrgetter/methodcaller)+运算符函数(add/mul/lt);比 lambda 快明确」,就理解了 operator 是什么。

二、itemgetter:按下标/键取值

理解 itemgetter:

itemgetter(k):返回一个函数,取 obj[k]
  f = itemgetter(1)
  f(["a","b","c"])  → "b"(取下标 1)
  f({"age": 25, ...}) 不行(itemgetter(键) 才对字典)
  itemgetter("age")({"age":25})  → 25(按键取)

取多个(返回元组):
  itemgetter(0, 2)(["a","b","c","d"])  → ("a", "c")
  → 一次取多个位置,组成元组
  用于多级排序:
  sorted(data, key=itemgetter("dept", "salary"))
  # 先按 dept 排,dept 相同再按 salary

最典型:sorted/max/min 的 key
  # 按元组第 2 项排序
  sorted([(1,'c'),(2,'a'),(3,'b')], key=itemgetter(1))
  → [(2,'a'),(3,'b'),(1,'c')]
  # 找 score 最高的记录
  max(records, key=itemgetter("score"))

vs lambda:
  key=itemgetter(1)       # 更快、更明确
  key=lambda x: x[1]      # 慢一点、要读 lambda

支持任何 __getitem__ 的对象:
  列表、元组(下标)、字典(键)、字符串(下标)
  itemgetter(0)("abc")  → "a"

所以 itemgetter(k)取 obj[k](下标或键),取多个返回元组(多级排序),排序 key 最常用

itemgetter(k):返回一个函数、取 obj[k]——f = itemgetter(1)f(["a","b","c"]) → “b”(取下标 1)、itemgetter("age")({"age":25}) → 25(按键取)。取多个(返回元组)itemgetter(0, 2)(["a","b","c","d"])("a", "c")(一次取多个位置组成元组、用于多级排序 sorted(data, key=itemgetter("dept", "salary")) 先按 dept 再按 salary)。最典型:sorted/max/min 的 key(按元组第 2 项排序 key=itemgetter(1)、找 score 最高 max(records, key=itemgetter("score")))。vs lambdakey=itemgetter(1) 更快更明确、key=lambda x: x[1] 慢一点。支持任何 __getitem__ 的对象(列表、元组、字典、字符串)。理解「itemgetter(k)取 objk;取多个返回元组(多级排序);排序/max/min 的 key 最常用;比 lambda 快;支持任何__getitem__对象」,就掌握了 itemgetter。

三、attrgetter:按属性取值

理解 attrgetter:

attrgetter('name'):返回函数,取 obj.name
  f = attrgetter("age")
  f(person)  → person.age

嵌套属性(属性链):
  attrgetter("addr.city")(user)  → user.addr.city
  → 点号分隔,自动逐级取

取多个属性:
  attrgetter("name", "age")(person)  → (person.name, person.age)

最典型:对象列表排序
  # 按对象的 age 属性排序
  sorted(people, key=attrgetter("age"))
  # 多级:先按 dept 再按 salary
  sorted(emps, key=attrgetter("dept", "salary"))
  # 找最年长的
  max(people, key=attrgetter("age"))

vs lambda:
  key=attrgetter("age")      # 明确、快
  key=lambda p: p.age        # 慢、啰嗦

itemgetter vs attrgetter(关键区分):
  itemgetter → 用于"下标/键"(x[k]):列表、字典、元组
  attrgetter → 用于"属性"(x.attr):对象
  → 数据是字典用 itemgetter("key")、是对象用 attrgetter("attr")

常见混淆:
  字典的值:itemgetter("age")(不是 attrgetter!字典不是属性)
  对象的字段:attrgetter("age")

所以 attrgetter('a')取 obj.a(属性),支持嵌套 a.b、取多个;对象排序 key 用它

attrgetter('name'):返回函数、取 obj.name——f = attrgetter("age")f(person)person.age嵌套属性(属性链)attrgetter("addr.city")(user)user.addr.city(点号分隔、自动逐级取)。取多个属性attrgetter("name", "age")(person)(person.name, person.age)最典型:对象列表排序sorted(people, key=attrgetter("age"))、多级 attrgetter("dept", "salary")max(people, key=attrgetter("age")))。itemgetter vs attrgetter(关键区分)itemgetter 用于「下标/键」(x[k]):列表、字典、元组;attrgetter 用于「属性」(x.attr):对象——数据是字典用 itemgetter("key")、是对象用 attrgetter("attr")常见混淆:字典的值用 itemgetter("age")(不是 attrgetter!字典不是属性)、对象的字段用 attrgetter("age")。理解「attrgetter(‘a’)取 obj.a 属性;支持嵌套 a.b、取多个;对象排序 key 用它;★区分:itemgetter 用于下标/键(列表/字典)、attrgetter 用于属性(对象);字典用 itemgetter、对象用 attrgetter」,就掌握了 attrgetter。

四、methodcaller 与运算符函数

理解 methodcaller 和运算符函数:

methodcaller('method', *args, **kwargs):调用 obj.method(args)
  f = methodcaller("upper")
  f("hello")  → "HELLO"(调 "hello".upper())
  f = methodcaller("replace", "a", "b")
  f("banana")  → "bbnbnb"(调 s.replace("a","b"))
  → 带参数的方法调用也能封装

用途:
  sorted(words, key=methodcaller("lower"))   # 按小写排序
  map(methodcaller("strip"), lines)          # 每行 strip
  filter(methodcaller("startswith", "http"), urls)

vs lambda:
  methodcaller("lower")     # 明确
  lambda s: s.lower()       # 等价

运算符函数(operator.xxx):
  算术:add, sub, mul, truediv, floordiv, mod, pow, neg
  比较:lt, le, eq, ne, ge, gt
  逻辑/位:and_, or_, xor, not_, inv
  序列:getitem, setitem, delitem, contains, concat
  就地:iadd, imul...(+=、*= 对应)

用途——把运算符当函数传:
  reduce(operator.mul, nums)        # 连乘
  reduce(operator.add, lists, [])   # 拼接列表(虽然有更好写法)
  max(a, b, key=...)
  sorted(pairs, key=..., reverse=...)

  # operator.itemgetter 配 sorted 二级
  # operator.and_ 配 reduce 求交集

什么时候用运算符函数:
  ✓ 需要"把运算符作为函数传递"(reduce/map 里)
  ✗ 普通运算直接用 +/*(别 operator.add(a,b) 代替 a+b)

所以 methodcaller('m',args)调 obj.m(args);运算符函数(add/mul/lt)把运算符当函数传

methodcaller('method', *args, **kwargs):调用 obj.method(args)——methodcaller("upper")("hello") → “HELLO”、methodcaller("replace", "a", "b")("banana") → “bbnbnb”(带参数的方法调用也能封装)。用途sorted(words, key=methodcaller("lower"))map(methodcaller("strip"), lines)filter(methodcaller("startswith", "http"), urls)运算符函数(operator.xxx):算术(add/sub/mul/truediv/mod/pow)、比较(lt/le/eq/ne/ge/gt)、逻辑/位(and_/or_/not_)、序列(getitem/contains/concat)、就地(iadd/imul)。用途——把运算符当函数传reduce(operator.mul, nums) 连乘、reduce(operator.add, lists, [])什么时候用运算符函数:需要「把运算符作为函数传递」时用(reduce/map 里)、普通运算直接用 +/*(别用 operator.add(a,b) 代替 a+b)。理解「methodcaller(‘m’,args)调 obj.m(args)(带参数);运算符函数 add/mul/lt 把运算符当函数传(reduce/map 里);普通运算直接用运算符别用 operator」,就掌握了 methodcaller 和运算符函数。

五、配合 sorted/groupby/max

理解 operator 在这些函数里的实战:

配合 sorted(最常用):
  # 单级
  sorted(data, key=itemgetter(1))
  sorted(objs, key=attrgetter("age"))
  # 多级(一次取多个)
  sorted(data, key=itemgetter("dept", "salary"))
  # 降序
  sorted(data, key=itemgetter(1), reverse=True)
  # 混合升降序:用负号或多次 sort(稳定排序)
  data.sort(key=itemgetter("name"))
  data.sort(key=itemgetter("age"), reverse=True)  # 后排的优先级高

配合 max/min:
  max(records, key=itemgetter("score"))   # score 最高的记录
  min(people, key=attrgetter("age"))      # 最年轻的人

配合 itertools.groupby(必须先排序!):
  from itertools import groupby
  data.sort(key=itemgetter("dept"))       # 先按分组键排序
  for dept, group in groupby(data, key=itemgetter("dept")):
      print(dept, list(group))
  ⚠️ groupby 只分组"相邻的相同键",不排序会分错

配合 map/filter:
  map(methodcaller("upper"), strings)
  filter(itemgetter("active"), records)   # 保留 active 为真的

为什么这些场景 operator 好:
  ① 更快(C 实现,无 Python lambda 调用开销)
  ② 更明确(itemgetter(1) 一眼是"取第 1 项")
  ③ 多级排序 itemgetter(a, b) 比 lambda x: (x[a],x[b]) 简洁

所以 operator 配 sorted/max/groupby/map:更快更明确,多级排序 itemgetter(a,b)简洁

配合 sorted(最常用):单级 sorted(data, key=itemgetter(1))、多级 itemgetter("dept", "salary")、降序 reverse=True、混合升降序用多次 sort(稳定排序、后排的优先级高)。配合 max/minmax(records, key=itemgetter("score"))min(people, key=attrgetter("age"))配合 itertools.groupby(必须先排序!)data.sort(key=itemgetter("dept"))groupby(data, key=itemgetter("dept"))(groupby 只分组相邻的相同键、不排序会分错)。配合 map/filtermap(methodcaller("upper"), strings)filter(itemgetter("active"), records)为什么这些场景 operator 好① 更快(C 实现)、② 更明确、③ 多级排序 itemgetter(a, b) 比 lambda 简洁。理解「operator 配 sorted(单/多级/降序)/max-min/groupby(必须先排序)/map-filter;更快更明确;多级排序 itemgetter(a,b)简洁;groupby 只分组相邻相同键要先排序」,就掌握了实战配合。

六、总结与实践

总结 operator 模块:

三个取值工厂(最常用):
  itemgetter(k)    取 x[k](下标/键)→ 列表、字典、元组
  attrgetter(a)    取 x.a(属性)→ 对象
  methodcaller(m)  调 x.m()(方法)
  → 都能取多个 / 带参数(methodcaller)

运算符函数:
  operator.add/mul/sub/lt/eq... 把运算符当函数传
  → 用于 reduce/map(需要传函数时)

最常用场景:
  sorted/max/min 的 key(比 lambda 快、明确)
  多级排序 itemgetter/attrgetter(a, b)
  groupby(先排序,key=itemgetter)
  reduce(operator.mul 等)

关键区分:
  下标/键 → itemgetter(字典的值用它,不是 attrgetter)
  属性   → attrgetter
  方法   → methodcaller

vs lambda:
  operator:更快(C 实现)、更明确
  lambda:更灵活(任意逻辑)
  → 纯"取值/运算符"用 operator、复杂逻辑用 lambda

核心总结:
  operator 把运算符/取值变函数
  itemgetter 取下标键、attrgetter 取属性、methodcaller 调方法
  做 sorted/max/groupby 的 key,比 lambda 快且清晰

所以 operator:itemgetter 取下标键/attrgetter 取属性/methodcaller 调方法,key 比 lambda 快

三个取值工厂(最常用)itemgetter(k)(取 x[k] 下标/键、列表/字典/元组)、attrgetter(a)(取 x.a 属性、对象)、methodcaller(m)(调 x.m() 方法)——都能取多个/带参数。运算符函数operator.add/mul/lt 把运算符当函数传(用于 reduce/map)。最常用场景:sorted/max/min 的 key、多级排序、groupby(先排序)、reduce。关键区分:下标/键用 itemgetter(字典的值用它不是 attrgetter)、属性用 attrgetter、方法用 methodcaller。vs lambda:operator 更快更明确、lambda 更灵活(纯取值/运算符用 operator、复杂逻辑用 lambda)。理解「operator:itemgetter 取下标键/attrgetter 取属性/methodcaller 调方法;运算符函数把运算符当函数传;做 sorted/max/groupby 的 key 比 lambda 快明确;字典用 itemgetter、对象用 attrgetter」,就掌握了总结与实践。

记忆钩子:「operator 模块把 Python 的『运算符和取值操作』封装成『函数』,这样运算符/取值也能当参数传(key/reduce 的二元函数),比 lambda 更快(C 实现)更明确;★三个取值工厂:①itemgetter(k)返回函数取 objk,itemgetter(1)≈lambda x:x[1],能取多个 itemgetter(0,2)返回元组(用于多级排序)→用于列表/字典/元组②attrgetter(‘name’)取 obj.name(属性),支持嵌套 attrgetter(‘a.b’)、取多个→用于对象③methodcaller(‘upper’)调 obj.upper()(方法),能带参数 methodcaller(‘replace’,‘a’,‘b’)→调方法;★关键区分:下标/键用 itemgetter(字典的值用 itemgetter(‘key’)不是 attrgetter!)、属性用 attrgetter、方法用 methodcaller;★最典型用途是排序 key:sorted(people,key=attrgetter(‘age’))、sorted(data,key=itemgetter(1))、max(records,key=itemgetter(‘score’))、配 itertools.groupby(必须先按相同 key 排序);运算符函数 operator.add/mul/lt/eq 把+/*/</==变成函数,用于 reduce(operator.mul,nums)连乘等需要传函数的场景(普通运算直接用运算符别用 operator.add)」

七、常见误区与追问

  • 误区:字典按值排序要用 attrgetter。 用 itemgetter——字典是用「键」取值(d["age"]、走 __getitem__),所以 sorted(dicts, key=itemgetter("age"));attrgetter 是取「属性」(obj.age、走 .),用于对象;常见混淆是把字典的键当成属性,记住:下标/键(列表、字典、元组)用 itemgetter,对象的字段/属性用 attrgetter。
  • 误区:itemgetter 和 attrgetter 只能取一个值。 都能取多个——itemgetter(0, 2) 返回 (x[0], x[2]) 元组、attrgetter("name", "age") 返回 (x.name, x.age) 元组;这正好用于「多级排序」:sorted(data, key=itemgetter("dept", "salary")) 会先按 dept 排、dept 相同再按 salary 排(元组比较是逐项比较),比 lambda x: (x["dept"], x["salary"]) 更简洁。
  • 误区:operator 模块只是 lambda 的替代,没必要用。 有实际优势——① 更快:itemgetter/attrgetter 是 C 实现的,没有 Python 层 lambda 的函数调用开销,在排序大数据时差异明显;② 更明确:itemgetter(1) 一眼看出「取第 1 项」、attrgetter("age") 一眼看出「取 age 属性」,比 lambda x: x[1] 意图更清晰;③ 支持多级取值(取元组);所以在 sorted/max/groupby 的 key 这类高频场景,operator 是更好的选择。
  • 误区:groupby 不用排序也能正确分组。 不能——itertools.groupby 只把「相邻的、键相同的」元素分到一组,遇到键变化就开新组;如果数据没按分组键排序,相同键的元素分散在各处,会被分成多个组(分错);所以用 groupby 前必须先按分组键排序:data.sort(key=itemgetter("dept")); groupby(data, key=itemgetter("dept"));这是 groupby 最常见的坑。
  • 追问:itemgetter、attrgetter、methodcaller 分别在什么场景用? 按「怎么取值」区分:① itemgetter(k) 用于「按下标或键取值」(obj[k])——列表/元组按下标 itemgetter(1)、字典按键 itemgetter("age")、字符串按下标;② attrgetter(“attr”) 用于「按属性取值」(obj.attr)——对象的字段,支持嵌套属性链 attrgetter("addr.city");③ methodcaller(“method”, args) 用于「调用对象的方法」(obj.method(args))——如 methodcaller("lower") 调 str.lower()、methodcaller("get", "key") 调 dict.get();三者最常见的用途都是给 sorted/max/min/groupby/map 传 key 或映射函数,比写 lambda 更快更明确;简单记:下标键用 itemgetter、属性用 attrgetter、方法用 methodcaller。
  • 追问:operator 里的运算符函数(如 operator.mul)什么时候用? 主要在「需要把运算符本身当作函数传递」的场景用,最典型是 functools.reduce——reduce(operator.mul, nums) 做连乘、reduce(operator.add, lists, []) 拼接(虽然拼接有更好写法)、reduce(operator.or_, sets) 求集合并集;此外 sorted/max 的比较、需要动态选择运算的场合也可能用到;但要注意:普通的算术运算直接写运算符就好(a + b 而不是 operator.add(a, b)),operator 的运算符函数只在「运算符不能直接写、必须传一个函数进去」时才有意义;求和、求积、极值这些有专门内置(sum、math.prod、max/min)时优先用内置,比 reduce + operator 更清晰。
  • 追问:怎么用 operator 做「先按部门升序、再按薪资降序」这种混合排序? 因为 Python 的 sort 是稳定排序(相等元素保持原顺序),可以「分多次排序、从次要键到主要键」:先按次要键排、再按主要键排,最后主要键的顺序占主导、主要键相同的保持次要键的顺序;「先按部门升序、再按薪资降序」写成:data.sort(key=itemgetter("salary"), reverse=True)(先按薪资降序),再 data.sort(key=itemgetter("dept"))(再按部门升序)——最终部门升序、同部门内薪资降序;如果所有键都同方向(都升或都降),可以一次搞定 sorted(data, key=itemgetter("dept", "salary"))(取元组多级比较);只有「不同键不同方向」时才需要分多次 sort(利用稳定性)。

八、加强记忆

operator 模块把 Python 的「运算符和取值操作」封装成「函数」,这样运算符/取值也能当参数传(key/reduce 的二元函数),比 lambda 更快(C 实现)更明确。三个取值工厂itemgetter(k) 返回函数取 obj[k](下标或键,itemgetter(1)lambda x: x[1],能取多个 itemgetter(0, 2) 返回元组用于多级排序)→ 用于列表/字典/元组;attrgetter('name')obj.name(属性,支持嵌套 attrgetter('a.b')、取多个)→ 用于对象;methodcaller('upper')obj.upper()(方法,能带参数 methodcaller('replace', 'a', 'b'))→ 调方法。关键区分:下标/键用 itemgetter(字典的值用 itemgetter("key") 不是 attrgetter)、属性用 attrgetter、方法用 methodcaller。最典型用途是排序 keysorted(people, key=attrgetter("age"))sorted(data, key=itemgetter(1))max(records, key=itemgetter("score"))、配 itertools.groupby(必须先按相同 key 排序)。运算符函数 operator.add/mul/lt/eq+/*/</== 变成函数,用于 reduce(operator.mul, nums) 等需要传函数的场景(普通运算直接用运算符)。一句话「operator 把运算符/取值变函数;itemgetter 取下标键(列表/字典)、attrgetter 取属性(对象)、methodcaller 调方法;做 sorted/max/groupby 的 key 比 lambda 快且明确、能取多个做多级排序;运算符函数用于 reduce 等传函数场景」。