CodeWalk

operator模块:itemgetter/attrgetter/methodcaller高级用法

作者:屠龙少年 · 2026-05-30 12:55

请介绍Python operator模块中itemgetterattrgettermethodcaller的用法和原理。与lambda相比,它们在性能和可读性上有什么优势?给出在排序、分组和数据库查询中的实际应用场景:如何用itemgetter替代lambda x: x[1]实现多级排序?如何用attrgetter替代lambda x: x.name?如何用methodcaller替代lambda x: x.strip()

回答

屠龙少年

itemgetter:按索引/键获取元素,替代索引lambda。

from operator import itemgetter, attrgetter, methodcaller

data = [('Alice', 25, 'NY'), ('Bob', 30, 'LA'), ('Charlie', 25, 'SF')]

# 多级排序:先年龄后名字
sorted(data, key=itemgetter(1, 0))
# 等价于 lambda x: (x[1], x[0])

# 获取多列:一次返回元组
get_name_city = itemgetter(0, 2)
for row in data:
    name, city = get_name_city(row)
    print(name, city)

attrgetter:按属性名获取,替代属性访问lambda。

from dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int
    city: str

people = [Person('Alice', 25, 'NY'), Person('Bob', 30, 'LA')]

# 按年龄排序
sorted(people, key=attrgetter('age'))
# 多级排序
sorted(people, key=attrgetter('city', 'age'))
# 等价于 lambda p: (p.city, p.age)

# 分组
from itertools import groupby
for city, group in groupby(sorted(people, key=attrgetter('city')), attrgetter('city')):
    print(city, list(group))

methodcaller:调用对象方法,替代方法调用lambda。

strings = ['  hello  ', 'WORLD', '  Python  ']

# 调用strip
processed = list(map(methodcaller('strip'), strings))
# 等价于 [s.strip() for s in strings]

# 带参数调用
methodcaller('replace', 'old', 'new')  # 调用 s.replace('old', 'new')

性能对比: | 方式 | 可读性 | 速度 | |------|--------|------| | lambda x: x[1] | 一般 | 较慢(Python级调用) | | itemgetter(1) | | (C级实现) | | lambda x: x.name | 一般 | 较慢 | | attrgetter('name') | | |

最佳实践:内置函数>operator模块>lambda,优先使用C级实现的operator函数提升性能。