一、什么是 operator 模块?
1.1 一句话定义
operator 模块把 Python 的运算符(+、-、*、>、== 等)封装成了函数,让你可以把运算符"传来传去"。
1.2 为什么需要它?
# ============ 问题场景 ============# 你想写一个通用函数,接收"运算方式"作为参数# ❌ 没有 operator 模块时,你得用 if/elif 或 lambda:def calculate(a, b, operation): if operation == "add": return a + b elif operation == "sub": return a - b elif operation == "mul": return a * b elif operation == "div": return a / b# 或者用 lambda:def calculate2(a, b, op_func): return op_func(a, b)calculate2(3, 4, lambda x, y: x + y) # 7calculate2(3, 4, lambda x, y: x * y) # 12# ✅ 有 operator 模块后,直接用现成函数:import operatordef calculate3(a, b, op_func): return op_func(a, b)calculate3(3, 4, operator.add) # 7(加法)calculate3(3, 4, operator.mul) # 12(乘法)# 更简洁、更清晰、性能也更好!
1.3 生活比喻
没有 operator: 你想让别人帮你"加"两个数 → 你得现场写一张纸条:"把这两个数加起来" (相当于每次写 lambda x, y: x + y)有 operator: 你直接递给别人一个"加法器" → 他拿来就用 (相当于直接传 operator.add)
1.4 导入方式
# 方式1:导入整个模块import operatoroperator.add(3, 4) # 7# 方式2:导入特定函数from operator import add, mul, itemgetteradd(3, 4) # 7# 方式3:导入所有(不推荐,容易命名冲突)from operator import *
二、算术运算函数
2.1 基本四则运算
import operator# ============ 加法 ============print(operator.add(3, 5)) # 8print(operator.add(3, 5) == 3 + 5) # True(等价于 3 + 5)print(operator.add("Hello, ", "World!")) # "Hello, World!"(字符串拼接)print(operator.add([1, 2], [3, 4])) # [1, 2, 3, 4](列表拼接)# ============ 减法 ============print(operator.sub(10, 3)) # 7print(operator.sub(10, 3) == 10 - 3) # True# ============ 乘法 ============print(operator.mul(4, 5)) # 20print(operator.mul("Ha", 3)) # "HaHaHa"(字符串重复)print(operator.mul([1, 2], 3)) # [1, 2, 1, 2, 1, 2](列表重复)# ============ 除法 ============print(operator.truediv(10, 3)) # 3.3333...(真除法,等价于 /)print(operator.floordiv(10, 3)) # 3(整除,等价于 //)# ============ 取余 ============print(operator.mod(10, 3)) # 1(等价于 10 % 3)# ============ 幂运算 ============print(operator.pow(2, 10)) # 1024(等价于 2 ** 10)# ============ 取反(负号) ============print(operator.neg(5)) # -5(等价于 -5)print(operator.neg(-3)) # 3# ============ 绝对值 ============print(operator.abs(-7)) # 7(等价于 abs(-7))# ============ 正号(很少用) ============print(operator.pos(-5)) # -5(等价于 +(-5),不变)
2.2 完整对照表
| | |
|---|
operator.add(a, b) | a + b | add(3, 5) |
operator.sub(a, b) | a - b | sub(10, 3) |
operator.mul(a, b) | a * b | mul(4, 5) |
operator.truediv(a, b) | a / b | truediv(10, 3) |
operator.floordiv(a, b) | a // b | floordiv(10, 3) |
operator.mod(a, b) | a % b | mod(10, 3) |
operator.pow(a, b) | a ** b | pow(2, 10) |
operator.neg(a) | -a | neg(5) |
operator.pos(a) | +a | pos(-5) |
operator.abs(a) | abs(a) | abs(-7) |
2.3 原地运算(In-place)
import operator# 原地运算:修改对象本身(对可变对象有效)# 等价于 a += b, a -= b 等a = [1, 2, 3]b = [4, 5]# operator.iadd 等价于 a += bresult = operator.iadd(a, b)print(result) # [1, 2, 3, 4, 5]print(a) # [1, 2, 3, 4, 5](a 本身被修改了!)print(result is a) # True(返回的就是 a 本身)# 对比普通 add:a = [1, 2, 3]b = [4, 5]result = operator.add(a, b)print(result) # [1, 2, 3, 4, 5]print(a) # [1, 2, 3](a 没变!add 创建了新列表)# 完整对照:# operator.iadd(a, b) ↔ a += b# operator.isub(a, b) ↔ a -= b# operator.imul(a, b) ↔ a *= b# operator.itruediv(a, b) ↔ a /= b# operator.ifloordiv(a, b) ↔ a //= b# operator.imod(a, b) ↔ a %= b# operator.ipow(a, b) ↔ a **= b# 对不可变对象(int, str),iadd 和 add 效果一样x = 5y = operator.iadd(x, 3) # 等价于 x += 3print(y) # 8print(x) # 5(int 不可变,x 没变)
2.4 矩阵运算(@ 运算符)
import operator# operator.matmul 等价于 @ 运算符(矩阵乘法,Python 3.5+)# 需要 numpy 等库支持import numpy as npA = np.array([[1, 2], [3, 4]])B = np.array([[5, 6], [7, 8]])# 以下两种写法等价:result1 = A @ Bresult2 = operator.matmul(A, B)print(result1)# [[19 22]# [43 50]]# 原地版本operator.imatmul(A, B) # A @= B
三、比较运算函数
3.1 基本比较
import operator# ============ 等于 ============print(operator.eq(3, 3)) # True(等价于 3 == 3)print(operator.eq(3, 4)) # Falseprint(operator.eq("abc", "abc")) # True# ============ 不等于 ============print(operator.ne(3, 4)) # True(等价于 3 != 4)print(operator.ne(3, 3)) # False# ============ 小于 ============print(operator.lt(3, 5)) # True(等价于 3 < 5)print(operator.lt(5, 3)) # False# ============ 小于等于 ============print(operator.le(3, 3)) # True(等价于 3 <= 3)print(operator.le(3, 5)) # Trueprint(operator.le(5, 3)) # False# ============ 大于 ============print(operator.gt(5, 3)) # True(等价于 5 > 3)print(operator.gt(3, 5)) # False# ============ 大于等于 ============print(operator.ge(5, 5)) # True(等价于 5 >= 5)print(operator.ge(5, 3)) # Trueprint(operator.ge(3, 5)) # False
3.2 完整对照表
| | |
|---|
operator.eq(a, b) | a == b | eq(3, 3) |
operator.ne(a, b) | a != b | ne(3, 4) |
operator.lt(a, b) | a < b | lt(3, 5) |
operator.le(a, b) | a <= b | le(3, 3) |
operator.gt(a, b) | a > b | gt(5, 3) |
operator.ge(a, b) | a >= b | ge(5, 5) |
3.3 实际应用:自定义排序
import operator# 场景:按不同条件排序students = [ {"name": "张三", "age": 20, "score": 92}, {"name": "李四", "age": 22, "score": 85}, {"name": "王五", "age": 21, "score": 98}, {"name": "赵六", "age": 20, "score": 88},]# 按分数降序排列# 方法1:用 lambdaby_score_1 = sorted(students, key=lambda s: s["score"], reverse=True)# 方法2:用 operator.itemgetter(更简洁、更快)by_score_2 = sorted(students, key=operator.itemgetter("score"), reverse=True)for s in by_score_2: print(f" {s['name']}: {s['score']}分")# 输出:# 王五: 98分# 张三: 92分# 赵六: 88分# 李四: 85分# 多条件排序:先按年龄升序,再按分数降序by_age_score = sorted(students, key=operator.itemgetter("age", "score"))# 注意:itemgetter 多字段时,都是升序# 如果要一个升序一个降序,需要技巧:by_age_score = sorted(students, key=lambda s: (s["age"], -s["score"]))
四、逻辑运算函数
import operator# ============ 逻辑与 ============print(operator.and_(True, True)) # True(等价于 True and True)print(operator.and_(True, False)) # Falseprint(operator.and_(1, 0)) # 0(按位与,对整数)# ⚠️ 注意:operator.and_ 对布尔值是逻辑与,对整数是按位与!# 末尾有下划线是因为 and 是 Python 关键字,不能做函数名# ============ 逻辑或 ============print(operator.or_(True, False)) # True(等价于 True or False)print(operator.or_(False, False)) # Falseprint(operator.or_(1, 0)) # 1(按位或)# ============ 逻辑非 ============print(operator.not_(True)) # False(等价于 not True)print(operator.not_(False)) # Trueprint(operator.not_(0)) # Trueprint(operator.not_("")) # True(空字符串是假值)print(operator.not_("hello")) # False# ============ 异或 ============print(operator.xor(True, False)) # True(不同为True)print(operator.xor(True, True)) # False(相同为False)print(operator.xor(5, 3)) # 6(按位异或:101 ^ 011 = 110)# ============ 真值测试 ============print(operator.truth(1)) # True(等价于 bool(1))print(operator.truth(0)) # Falseprint(operator.truth("")) # Falseprint(operator.truth("hello")) # Trueprint(operator.truth([])) # Falseprint(operator.truth([1])) # True# ============ 判断是否为假 ============# Python 3.x 中没有直接的 is_false,用 not_ 代替print(operator.not_(0)) # True(0 是假的)
4.1 完整对照表
| | |
|---|
operator.and_(a, b) | a and b | |
operator.or_(a, b) | a or b | |
operator.not_(a) | not a | |
operator.xor(a, b) | a ^ b | |
operator.truth(a) | bool(a) | |
operator.invert(a) | ~a | |
📌 为什么有下划线?and、or、not、is 是 Python 关键字,不能做函数名,所以加了下划线:and_、or_、not_、is_。
五、位运算函数
import operator# ============ 按位与 ============print(operator.and_(12, 10)) # 8# 12 = 1100# 10 = 1010# & = 1000 = 8# ============ 按位或 ============print(operator.or_(12, 10)) # 14# 12 = 1100# 10 = 1010# | = 1110 = 14# ============ 按位异或 ============print(operator.xor(12, 10)) # 6# 12 = 1100# 10 = 1010# ^ = 0110 = 6# ============ 按位取反 ============print(operator.invert(5)) # -6(等价于 ~5)# 5 = 0000...0101# ~5 = 1111...1010 = -6(补码)# ============ 左移 ============print(operator.lshift(1, 4)) # 16(等价于 1 << 4)# 1 左移 4 位:0001 → 10000 = 16# ============ 右移 ============print(operator.rshift(16, 4)) # 1(等价于 16 >> 4)# 16 右移 4 位:10000 → 0001 = 1# ============ 完整对照 ============# operator.and_(a, b) ↔ a & b# operator.or_(a, b) ↔ a | b# operator.xor(a, b) ↔ a ^ b# operator.invert(a) ↔ ~a# operator.lshift(a, b) ↔ a << b# operator.rshift(a, b) ↔ a >> b# 原地版本:# operator.iand(a, b) ↔ a &= b# operator.ior(a, b) ↔ a |= b# operator.ixor(a, b) ↔ a ^= b# operator.ilshift(a, b) ↔ a <<= b# operator.irshift(a, b) ↔ a >>= b
六、序列操作函数
6.1 concat —— 拼接
import operator# 等价于 + 运算符(用于序列)print(operator.concat("Hello, ", "World!")) # "Hello, World!"print(operator.concat([1, 2], [3, 4])) # [1, 2, 3, 4]print(operator.concat((1, 2), (3, 4))) # (1, 2, 3, 4)# 等价于:print("Hello, " + "World!") # 一样的结果print([1, 2] + [3, 4]) # 一样的结果
6.2 contains —— 包含判断
import operator# 等价于 in 运算符# 注意参数顺序:contains(容器, 元素)print(operator.contains([1, 2, 3], 2)) # True(2 in [1,2,3])print(operator.contains([1, 2, 3], 5)) # Falseprint(operator.contains("hello world", "world")) # Trueprint(operator.contains({"a": 1, "b": 2}, "a")) # True(键存在)print(operator.contains({"a": 1, "b": 2}, 1)) # False(值不算)# 等价于:print(2 in [1, 2, 3]) # Trueprint("world" in "hello world") # True
6.3 countOf —— 计数
import operator# 统计元素出现次数print(operator.countOf([1, 2, 3, 2, 2, 4], 2)) # 3print(operator.countOf("hello world", "l")) # 3print(operator.countOf("hello world", "z")) # 0# 等价于:print([1, 2, 3, 2, 2, 4].count(2)) # 3print("hello world".count("l")) # 3
6.4 indexOf —— 查找索引
import operator# 返回第一次出现的索引(找不到报错)print(operator.indexOf([10, 20, 30, 20], 20)) # 1(第一次出现在索引1)print(operator.indexOf("hello", "l")) # 2# 找不到会报错:# operator.indexOf([1, 2, 3], 5) # ❌ ValueError: 5 is not in list# 等价于:print([10, 20, 30, 20].index(20)) # 1print("hello".index("l")) # 2
6.5 getitem / setitem / delitem —— 下标操作
import operator# ============ getitem:获取元素 ============# 等价于 obj[key]my_list = [10, 20, 30, 40, 50]print(operator.getitem(my_list, 0)) # 10(等价于 my_list[0])print(operator.getitem(my_list, -1)) # 50(等价于 my_list[-1])print(operator.getitem(my_list, slice(1, 4))) # [20, 30, 40](切片)my_dict = {"name": "张三", "age": 25}print(operator.getitem(my_dict, "name")) # "张三"(等价于 my_dict["name"])my_str = "Hello"print(operator.getitem(my_str, 1)) # "e"(等价于 my_str[1])# ============ setitem:设置元素 ============# 等价于 obj[key] = valuemy_list = [1, 2, 3, 4, 5]operator.setitem(my_list, 0, 100)print(my_list) # [100, 2, 3, 4, 5](等价于 my_list[0] = 100)operator.setitem(my_list, slice(1, 3), [200, 300])print(my_list) # [100, 200, 300, 4, 5](切片赋值)my_dict = {"a": 1}operator.setitem(my_dict, "b", 2)print(my_dict) # {'a': 1, 'b': 2}(等价于 my_dict["b"] = 2)# ============ delitem:删除元素 ============# 等价于 del obj[key]my_list = [1, 2, 3, 4, 5]operator.delitem(my_list, 0)print(my_list) # [2, 3, 4, 5](等价于 del my_list[0])operator.delitem(my_list, slice(0, 2))print(my_list) # [4, 5](删除前两个)my_dict = {"a": 1, "b": 2, "c": 3}operator.delitem(my_dict, "b")print(my_dict) # {'a': 1, 'c': 3}(等价于 del my_dict["b"])
6.6 length_hint —— 长度估计
import operator# 返回对象的长度(或估计长度)print(operator.length_hint([1, 2, 3])) # 3print(operator.length_hint("hello")) # 5print(operator.length_hint(iter([1, 2, 3]))) # 3(迭代器的估计长度)# 主要用于内部优化(如 list 预分配内存)# 日常开发很少直接用
七、⭐ itemgetter —— 获取下标(最常用!)
7.1 基本用法
from operator import itemgetter# itemgetter(key) 返回一个函数,该函数接收一个对象,返回 obj[key]# ============ 获取列表元素 ============get_first = itemgetter(0) # 创建一个"获取第0个元素"的函数get_last = itemgetter(-1) # 创建一个"获取最后一个元素"的函数print(get_first([10, 20, 30])) # 10print(get_last([10, 20, 30])) # 30# 等价于:# get_first = lambda x: x[0]# get_last = lambda x: x[-1]# ============ 获取字典值 ============get_name = itemgetter("name")get_age = itemgetter("age")person = {"name": "张三", "age": 25, "city": "北京"}print(get_name(person)) # "张三"print(get_age(person)) # 25# ============ 获取多个元素 ============get_first_and_last = itemgetter(0, -1) # 同时获取第一个和最后一个print(get_first_and_last([10, 20, 30, 40, 50])) # (10, 50)(返回元组)get_name_age = itemgetter("name", "age")print(get_name_age(person)) # ('张三', 25)
7.2 排序中的应用(最经典场景)
from operator import itemgetter# ============ 场景1:字典列表排序 ============students = [ {"name": "张三", "age": 20, "score": 92}, {"name": "李四", "age": 22, "score": 85}, {"name": "王五", "age": 21, "score": 98}, {"name": "赵六", "age": 20, "score": 88},]# 按分数排序by_score = sorted(students, key=itemgetter("score"), reverse=True)for s in by_score: print(f" {s['name']}: {s['score']}分")# 王五: 98分# 张三: 92分# 赵六: 88分# 李四: 85分# 多条件排序:先按年龄,再按分数by_age_score = sorted(students, key=itemgetter("age", "score"))for s in by_age_score: print(f" {s['name']}: {s['age']}岁, {s['score']}分")# 张三: 20岁, 92分# 赵六: 20岁, 88分# 王五: 21岁, 98分# 李四: 22岁, 85分# ============ 场景2:元组列表排序 ============data = [(1, "b"), (3, "a"), (2, "c"), (1, "a")]# 按第一个元素排序print(sorted(data, key=itemgetter(0)))# [(1, 'b'), (1, 'a'), (2, 'c'), (3, 'a')]# 按第二个元素排序print(sorted(data, key=itemgetter(1)))# [(3, 'a'), (1, 'a'), (1, 'b'), (2, 'c')]# 先按第一个,再按第二个print(sorted(data, key=itemgetter(0, 1)))# [(1, 'a'), (1, 'b'), (2, 'c'), (3, 'a')]# ============ 场景3:对比 lambda ============# 用 lambda:sorted(students, key=lambda s: s["score"])# 用 itemgetter(更快、更简洁):sorted(students, key=itemgetter("score"))# 性能对比(itemgetter 是 C 实现的,比 lambda 快)import timeitdata = [{"x": i} for i in range(1000)]# lambda 方式timeit.timeit(lambda: sorted(data, key=lambda d: d["x"]), number=1000)# itemgetter 方式(通常快 20-30%)timeit.timeit(lambda: sorted(data, key=itemgetter("x")), number=1000)
7.3 嵌套数据获取
from operator import itemgetter# 获取嵌套结构中的数据data = [ {"name": "张三", "scores": {"math": 90, "english": 85}}, {"name": "李四", "scores": {"math": 78, "english": 92}},]# 获取每个人的 scores 字典get_scores = itemgetter("scores")print(get_scores(data[0])) # {'math': 90, 'english': 85}# 获取嵌套中的值需要组合使用get_math = lambda x: x["scores"]["math"]# 或者用 itemgetter 嵌套:# 先取 scores,再取 mathget_math_score = lambda x: itemgetter("math")(x["scores"])print(get_math_score(data[0])) # 90print(get_math_score(data[1])) # 78
八、⭐ attrgetter —— 获取属性(非常常用!)
8.1 基本用法
from operator import attrgetter# attrgetter("attr") 返回一个函数,该函数返回 obj.attrclass Student: def __init__(self, name, age, score): self.name = name self.age = age self.score = score def __repr__(self): return f"Student({self.name}, {self.age}, {self.score})"students = [ Student("张三", 20, 92), Student("李四", 22, 85), Student("王五", 21, 98), Student("赵六", 20, 88),]# ============ 获取单个属性 ============get_name = attrgetter("name")get_score = attrgetter("score")print(get_name(students[0])) # "张三"(等价于 students[0].name)print(get_score(students[0])) # 92(等价于 students[0].score)# ============ 获取多个属性 ============get_name_score = attrgetter("name", "score")print(get_name_score(students[0])) # ('张三', 92)# ============ 排序 ============# 按分数降序by_score = sorted(students, key=attrgetter("score"), reverse=True)for s in by_score: print(f" {s.name}: {s.score}分")# 王五: 98分# 张三: 92分# 赵六: 88分# 李四: 85分# 多条件:先按年龄,再按分数by_age_score = sorted(students, key=attrgetter("age", "score"))
8.2 获取嵌套属性(用点号)
from operator import attrgetterclass Address: def __init__(self, city, street): self.city = city self.street = streetclass Person: def __init__(self, name, address): self.name = name self.address = addresspeople = [ Person("张三", Address("北京", "长安街")), Person("李四", Address("上海", "南京路")), Person("王五", Address("北京", "王府井")),]# 获取嵌套属性:用 "." 连接get_city = attrgetter("address.city")get_street = attrgetter("address.street")print(get_city(people[0])) # "北京"(等价于 people[0].address.city)print(get_street(people[1])) # "南京路"# 按城市排序by_city = sorted(people, key=attrgetter("address.city"))for p in by_city: print(f" {p.name}: {p.address.city}{p.address.street}")# 张三: 北京 长安街# 王五: 北京 王府井# 李四: 上海 南京路# 同时获取多个嵌套属性get_info = attrgetter("name", "address.city")print(get_info(people[0])) # ('张三', '北京')
8.3 attrgetter vs lambda 对比
from operator import attrgetterclass Point: def __init__(self, x, y): self.x = x self.y = ypoints = [Point(3, 4), Point(1, 2), Point(5, 0)]# 用 lambda:sorted(points, key=lambda p: p.x)# 用 attrgetter(更简洁、更快):sorted(points, key=attrgetter("x"))# 嵌套属性时优势更明显:# lambda: key=lambda p: p.address.city# attrgetter: key=attrgetter("address.city")
九、⭐ methodcaller —— 调用方法
9.1 基本用法
from operator import methodcaller# methodcaller("method_name", *args, **kwargs)# 返回一个函数,该函数调用 obj.method_name(*args, **kwargs)# ============ 调用字符串方法 ============to_upper = methodcaller("upper")to_lower = methodcaller("lower")to_strip = methodcaller("strip")print(to_upper("hello")) # "HELLO"(等价于 "hello".upper())print(to_lower("HELLO")) # "hello"print(to_strip(" hi ")) # "hi"# ============ 带参数的方法调用 ============# str.replace(old, new)replace_spaces = methodcaller("replace", " ", "_")print(replace_spaces("hello world foo")) # "hello_world_foo"# str.split(sep)split_by_comma = methodcaller("split", ",")print(split_by_comma("a,b,c,d")) # ['a', 'b', 'c', 'd']# str.startswith(prefix)starts_with_http = methodcaller("startswith", "http")print(starts_with_http("https://example.com")) # Trueprint(starts_with_http("ftp://example.com")) # False# ============ 列表方法 ============append_99 = methodcaller("append", 99)my_list = [1, 2, 3]append_99(my_list)print(my_list) # [1, 2, 3, 99]# ============ 排序方法 ============do_sort = methodcaller("sort")my_list = [3, 1, 4, 1, 5]do_sort(my_list)print(my_list) # [1, 1, 3, 4, 5]
9.2 实际应用:批量处理方法
from operator import methodcaller# 场景:批量处理字符串列表words = [" Hello ", " World ", " Python "]# 方法1:列表推导 + 方法调用cleaned_1 = [w.strip().lower() for w in words]# 方法2:用 methodcaller + mapstrip_lower = methodcaller("strip")# 注意:methodcaller 一次只能调一个方法,需要组合cleaned_2 = list(map(methodcaller("lower"), map(methodcaller("strip"), words)))print(cleaned_2) # ['hello', 'world', 'python']# 场景:对对象列表调用方法class Document: def __init__(self, title, content): self.title = title self.content = content def summarize(self, max_len=50): return self.content[:max_len] + "..." def word_count(self): return len(self.content.split())docs = [ Document("文章1", "Python 是一门优雅的编程语言,它的设计哲学强调代码的可读性。"), Document("文章2", "机器学习是人工智能的一个重要分支领域。"),]# 批量调用 word_count 方法get_word_count = methodcaller("word_count")counts = list(map(get_word_count, docs))print(counts) # [25, 15](大约)# 批量调用 summarize 方法(带参数)get_summary = methodcaller("summarize", 20)summaries = list(map(get_summary, docs))for s in summaries: print(f" {s}")
十、is_ 和 is_not —— 身份判断
import operator# ============ is_:判断是否为同一对象 ============a = [1, 2, 3]b = ac = [1, 2, 3]print(operator.is_(a, b)) # True(a 和 b 是同一个对象)print(operator.is_(a, c)) # False(内容相同,但不是同一个对象)# 等价于:print(a is b) # Trueprint(a is c) # False# ============ is_not:判断是否不是同一对象 ============print(operator.is_not(a, c)) # Trueprint(operator.is_not(a, b)) # False# 等价于:print(a is not c) # Trueprint(a is not b) # False# ============ 常见用途:过滤 None ============data = [1, None, 3, None, 5, None, 7]# 用 lambda:cleaned_1 = list(filter(lambda x: x is not None, data))# 用 operator(需要 functools.partial 或其他方式):# 实际上这个场景 lambda 更直观print(cleaned_1) # [1, 3, 5, 7]
十一、index 和 length_hint
import operator# ============ index:转为整数索引 ============# 等价于 __index__(),用于需要整数的场景print(operator.index(5)) # 5print(operator.index(True)) # 1(布尔值转整数)print(operator.index(False)) # 0# 用于切片等需要整数的地方my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]start = operator.index(2)end = operator.index(7)print(my_list[start:end]) # [2, 3, 4, 5, 6]# 对浮点数会报错:# operator.index(3.14) # ❌ TypeError# ============ length_hint:长度估计 ============print(operator.length_hint([1, 2, 3])) # 3print(operator.length_hint(iter(range(10)))) # 10
十二、综合实战案例
12.1 学生成绩管理系统
from operator import itemgetter, attrgetter, methodcallerimport functools# ============ 用字典存储 ============students = [ {"name": "张三", "age": 20, "scores": {"math": 92, "english": 85, "physics": 78}}, {"name": "李四", "age": 22, "scores": {"math": 88, "english": 92, "physics": 95}}, {"name": "王五", "age": 21, "scores": {"math": 98, "english": 76, "physics": 82}}, {"name": "赵六", "age": 20, "scores": {"math": 72, "english": 88, "physics": 90}},]# 1. 按数学成绩排序print("=== 数学成绩排名 ===")by_math = sorted(students, key=lambda s: s["scores"]["math"], reverse=True)for rank, s in enumerate(by_math, 1): print(f" 第{rank}名:{s['name']}({s['scores']['math']}分)")# 2. 计算每个人的总分print("\n=== 总分排名 ===")def total_score(student): return sum(student["scores"].values())by_total = sorted(students, key=total_score, reverse=True)for rank, s in enumerate(by_total, 1): total = total_score(s) print(f" 第{rank}名:{s['name']}(总分 {total})")# 3. 用 itemgetter 简化print("\n=== 按年龄排序 ===")by_age = sorted(students, key=itemgetter("age"))for s in by_age: print(f" {s['name']}: {s['age']}岁")# ============ 用类存储 ============class Student: def __init__(self, name, age, math, english, physics): self.name = name self.age = age self.math = math self.english = english self.physics = physics @property def total(self): return self.math + self.english + self.physics @property def average(self): return round(self.total / 3, 1) def __repr__(self): return f"{self.name}(总分{self.total})"students_obj = [ Student("张三", 20, 92, 85, 78), Student("李四", 22, 88, 92, 95), Student("王五", 21, 98, 76, 82), Student("赵六", 20, 72, 88, 90),]# 用 attrgetter 排序print("\n=== 对象排序 ===")by_total = sorted(students_obj, key=attrgetter("total"), reverse=True)for s in by_total: print(f" {s.name}: 总分{s.total}, 平均{s.average}")# 多条件:先按年龄,再按总分by_age_total = sorted(students_obj, key=attrgetter("age", "total"))
12.2 数据处理管道
from operator import itemgetter, methodcallerimport functools# 模拟 API 返回的数据api_response = [ {"id": 1, "title": " Python入门 ", "tags": "python,beginner,tutorial", "views": 1500}, {"id": 2, "title": " Flask实战 ", "tags": "flask,web,python", "views": 3200}, {"id": 3, "title": " 数据分析 ", "tags": "pandas,numpy,data", "views": 800}, {"id": 4, "title": " Django部署 ", "tags": "django,web,deploy", "views": 2100},]# 处理管道:# 1. 提取标题 → 2. 去空格 → 3. 转小写 → 4. 排序# 用 methodcaller 构建处理步骤strip_title = methodcaller("strip")to_lower = methodcaller("lower")# 提取并处理标题titles = [itemgetter("title")(item) for item in api_response]print("原始标题:", titles)# [' Python入门 ', ' Flask实战 ', ' 数据分析 ', ' Django部署 ']cleaned = [to_lower(strip_title(t)) for t in titles]print("处理后:", cleaned)# ['python入门', 'flask实战', '数据分析', 'django部署']# 按 views 排序by_views = sorted(api_response, key=itemgetter("views"), reverse=True)print("\n按浏览量排序:")for item in by_views: print(f" {item['title'].strip()}: {item['views']}次")# 提取 tags 并拆分get_tags = itemgetter("tags")split_comma = methodcaller("split", ",")all_tags = []for item in api_response: tags = split_comma(get_tags(item)) all_tags.extend(tags)print(f"\n所有标签:{all_tags}")print(f"标签数量:{len(all_tags)}")print(f"去重后:{sorted(set(all_tags))}")
12.3 自定义排序器工厂
from operator import itemgetter, attrgetterdef make_sorter(*keys, reverse=False): """ 创建一个排序函数 用法:sort_by_score = make_sorter("score", reverse=True) """ getter = itemgetter(*keys) if len(keys) > 1 else itemgetter(keys[0]) def sort_func(data_list): return sorted(data_list, key=getter, reverse=reverse) return sort_func# 创建不同的排序器sort_by_score = make_sorter("score", reverse=True)sort_by_age = make_sorter("age")sort_by_age_score = make_sorter("age", "score")# 使用data = [ {"name": "A", "age": 22, "score": 85}, {"name": "B", "age": 20, "score": 92}, {"name": "C", "age": 20, "score": 88},]print("按分数降序:")for item in sort_by_score(data): print(f" {item['name']}: {item['score']}")print("\n按年龄+分数:")for item in sort_by_age_score(data): print(f" {item['name']}: {item['age']}岁, {item['score']}分")
12.4 用 operator 实现函数式编程
from operator import add, mul, sub, itemgetterfrom functools import reduce, partialimport itertools# ============ reduce 累加 ============numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]# 求和total = reduce(add, numbers)print(f"求和:{total}") # 55# 求积product = reduce(mul, numbers)print(f"求积:{product}") # 3628800# 找最大值maximum = reduce(lambda a, b: a if a > b else b, numbers)# 或者直接用 max(numbers)# ============ partial 偏函数 ============# 固定一个参数,创建新函数# 创建一个"加10"的函数add_10 = partial(add, 10)print(add_10(5)) # 15print(add_10(20)) # 30# 创建一个"乘以2"的函数double = partial(mul, 2)print(double(7)) # 14# 批量应用numbers = [1, 2, 3, 4, 5]doubled = list(map(double, numbers))print(doubled) # [2, 4, 6, 8, 10]added = list(map(add_10, numbers))print(added) # [11, 12, 13, 14, 15]# ============ accumulate 累积 ============# itertools.accumulate 默认用加法print(list(itertools.accumulate([1, 2, 3, 4, 5])))# [1, 3, 6, 10, 15](累积和)# 用乘法print(list(itertools.accumulate([1, 2, 3, 4, 5], mul)))# [1, 2, 6, 24, 120](累积积,即阶乘)# 用自定义函数print(list(itertools.accumulate([1, 2, 3, 4, 5], lambda a, b: a + b * 2)))# [1, 5, 11, 19, 29]
十三、operator 模块完整函数列表
13.1 按类别分组
═══════════════════════════════════════════════════════ 算术运算═══════════════════════════════════════════════════════ add(a, b) a + b sub(a, b) a - b mul(a, b) a * b truediv(a, b) a / b floordiv(a, b) a // b mod(a, b) a % b pow(a, b) a ** b matmul(a, b) a @ b neg(a) -a pos(a) +a abs(a) abs(a) 原地版本:iadd, isub, imul, itruediv, ifloordiv, imod, ipow, imatmul═══════════════════════════════════════════════════════ 比较运算═══════════════════════════════════════════════════════ eq(a, b) a == b ne(a, b) a != b lt(a, b) a < b le(a, b) a <= b gt(a, b) a > b ge(a, b) a >= b═══════════════════════════════════════════════════════ 逻辑/位运算═══════════════════════════════════════════════════════ and_(a, b) a and b / a & b or_(a, b) a or b / a | b not_(a) not a xor(a, b) a ^ b invert(a) ~a lshift(a, b) a << b rshift(a, b) a >> b truth(a) bool(a) 原地版本:iand, ior, ixor, ilshift, irshift═══════════════════════════════════════════════════════ 身份判断═══════════════════════════════════════════════════════ is_(a, b) a is b is_not(a, b) a is not b═══════════════════════════════════════════════════════ 序列操作═══════════════════════════════════════════════════════ concat(a, b) a + b(序列拼接) contains(a, b) b in a countOf(a, b) a.count(b) indexOf(a, b) a.index(b) getitem(a, b) a[b] setitem(a, b, c) a[b] = c delitem(a, b) del a[b] length_hint(obj) len(obj) 的估计═══════════════════════════════════════════════════════ 属性/下标/方法获取器(⭐最常用)═══════════════════════════════════════════════════════ itemgetter(key) 返回 obj[key] 的函数 attrgetter(attr) 返回 obj.attr 的函数 methodcaller(name) 返回 obj.name() 的函数═══════════════════════════════════════════════════════ 其他═══════════════════════════════════════════════════════ index(a) a.__index__()
十四、性能对比
import operatorimport timeit# 测试数据data = [{"x": i, "y": i * 2} for i in range(10000)]# ============ 排序性能对比 ============# 方式1:lambdatime_lambda = timeit.timeit( lambda: sorted(data, key=lambda d: d["x"]), number=100)# 方式2:itemgettertime_itemgetter = timeit.timeit( lambda: sorted(data, key=operator.itemgetter("x")), number=100)print(f"lambda: {time_lambda:.4f}s")print(f"itemgetter: {time_itemgetter:.4f}s")print(f"加速比: {time_lambda/time_itemgetter:.2f}x")# 通常 itemgetter 快 20-40%# ============ 运算性能对比 ============import randompairs = [(random.randint(1, 100), random.randint(1, 100)) for _ in range(100000)]# lambda 方式time_lambda_add = timeit.timeit( lambda: [a + b for a, b in pairs], number=10)# operator 方式time_operator_add = timeit.timeit( lambda: list(map(operator.add, *zip(*pairs))), number=10)# 对于简单运算,差距不大# 对于排序的 key 函数,itemgetter/attrgetter 优势明显
十五、常见使用场景总结
| | |
|---|
| itemgetter("key") | sorted(data, key=itemgetter("score")) |
| attrgetter("attr") | sorted(objs, key=attrgetter("age")) |
| itemgetter("a", "b") | sorted(data, key=itemgetter("age", "score")) |
| attrgetter("a.b.c") | sorted(objs, key=attrgetter("addr.city")) |
| methodcaller("upper") | list(map(methodcaller("strip"), texts)) |
| reduce(add, list) | reduce(add, [1,2,3,4,5]) |
| partial(add, 10) | add_10 = partial(add, 10) |
| | apply_operation(a, b, operator.mul) |
十六、学习路径建议
第1天:理解为什么需要 operator(对比 lambda)第2天:掌握 itemgetter(排序中最常用)第3天:掌握 attrgetter(对象排序)第4天:掌握 methodcaller(批量方法调用)第5天:了解算术/比较/逻辑运算函数第6天:结合 functools(reduce, partial)做函数式编程第7天:在实际项目中应用(排序、数据处理)
十七、一句话总结
operator 模块 = 把运算符变成函数,让你可以把"操作"作为参数传递。
最常用的三个:
itemgetterattrgettermethodcaller