news 2026/10/30 3:01:51

跟老齐学Python之大话题小函数(1)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
跟老齐学Python之大话题小函数(1)

前言


"函数"在 Python 里是个大话题,但真正好用的函数往往很小——只做一件事、 名字说得清、输入输出一看就懂。这一篇就围绕"小函数"这个思路,把函数式风格的 常用工具串一遍:函数当值用、lambda、map/filter/sorted/reduce这些内置工具怎么配合小函数干活。


有个反复出现的误解:以为map、filter返回的是列表。这是 Python 2 时代 的老印象。Python 3 里它们返回的是惰性的迭代器(iterator),需要时才计算 下一个元素,而且只能遍历一次。忘了这一点,就会遇到"打印一次之后再遍历 就空了"的诡异现象。


Python 2 已于 2020 年 1 月 1 日停止维护。本文一律用 Python 3 的写法:print是函数不是语句,map/filter/zip返回迭代器,reduce需要从functools导入——这些和 Python 2 都不一样。


一、函数是可以到处传的值


前面说过函数是对象。既然它是值,就能被放进变量、列表、字典,也能当参数传给 别的函数。所谓"小函数",就是把这些小函数当作积木,交给通用工具去组合。


# 适用于 Python 3.8+

def is_positive(x):
return x > 0

def square(x):
return x * x

nums = [-2, -1, 0, 1, 2]

# 用小函数做"过滤 + 变换"
result = [square(n) for n in nums if is_positive(n)]
print(result) # [1, 4]

这两个函数各只有一行,职责单一,名字就是文档。这就是"小函数"的样板。


二、lambda:一次性的小函数


lambda用来写只包含一个表达式的匿名函数,适合当参数就地传。它的能力 是def的子集:不能包含语句、不能写多行逻辑、不能有return。


# 适用于 Python 3.8+

pairs = [("b", 2), ("a", 3), ("c", 1)]

# 按元组第二个元素排序
by_second = sorted(pairs, key=lambda p: p[1])
print(by_second) # [('c', 1), ('b', 2), ('a', 3)]

# 等价于先定义小函数的写法
def second(p):
return p[1]

print(sorted(pairs, key=second)) # 结果一样

经验法则:能用def写清楚就别用lambda;只有当函数小到"一行看完、 不值得起名字"时,lambda才划算。


三、map / filter:惰性的转换与筛选


map(func, iterable)把func依次作用到每个元素上,返回一个迭代器;filter(func, iterable)保留让func返回真值的元素,也返回迭代器。 要看结果,用list(...)取出来。


# 适用于 Python 3.8+

nums = [1, 2, 3, 4]

squares = list(map(lambda x: x * x, nums))
print(squares) # [1, 4, 9, 16]

evens = list(filter(lambda x: x % 2 == 0, range(10)))
print(evens) # [0, 2, 4, 6, 8]

同样的事用推导式往往更清楚,这也是现在的常见推荐:


# 适用于 Python 3.8+

nums = [1, 2, 3, 4]
print([x * x for x in nums]) # 等价于 map
print([x for x in range(10) if x % 2 == 0]) # 等价于 filter

map和filter的返回值是迭代器,迭代器是"一次性的":遍历过就空了。


# 适用于 Python 3.8+

m = map(str, [1, 2, 3])
print(list(m)) # ['1', '2', '3']
print(list(m)) # [] 已经空了

四、sorted 的 key 与 reduce


sorted(iterable, key=..., reverse=...)返回新列表,不改变原对象;key接 受一个函数,用来算排序依据。要"原地排序"用列表自己的list.sort(),它返回None。


# 适用于 Python 3.8+

words = ["banana", "kiwi", "Apple"]
print(sorted(words, key=str.lower)) # ['Apple', 'banana', 'kiwi']
print(sorted(words, key=len)) # ['kiwi', 'Apple', 'banana']

functools.reduce(function, iterable, initial)把两个参数的函数累积地作用 到整个序列上,返回一个值;initial可选,作为初始累积值。


# 适用于 Python 3.8+

from functools import reduce

print(reduce(lambda a, b: a + b, [1, 2, 3, 4])) # 10
print(reduce(lambda a, b: a + b, [1, 2, 3, 4], 100)) # 110
print(reduce(lambda a, b: a * b, [1, 2, 3, 4], 1)) # 24

注意reduce是functools里的函数,必须导入;它不是内置函数(Python 2 里曾是内置的,3 里移走了)。


五、all / any / min / max


这几个内置函数配合小函数同样好用,且都接受key或生成器表达式:


# 适用于 Python 3.8+

print(all(x > 0 for x in [1, 2, 3])) # True
print(any(x > 2 for x in [1, 2, 3])) # True

people = [("Tom", 30), ("Ann", 25)]
print(max(people, key=lambda p: p[1])) # ('Tom', 30)
print(min(people, key=lambda p: p[1])) # ('Ann', 25)

all在遇到第一个假值时就短路返回,any遇到第一个真值就短路,两者都不会遍历完整个序列(如果没必要的话)。


六、把逻辑拆成小函数:一个完整例子


下面用一组小函数处理一份"学生成绩",把过滤、变换、排序、聚合各交给一个职责 单一的函数,最后串起来。这种"每个函数只做一件事、用一个词说清"的写法,是最 容易测试和维护的。


# 适用于 Python 3.8+

students = [
("Tom", 82),
("Ann", 95),
("Bob", 67),
("Amy", 95),
]

def is_pass(student):
"""分数不低于 60 算及格。"""
return student[1] >= 60

def name_of(student):
"""取出姓名。"""
return student[0]

def score_of(student):
"""取出分数。"""
return student[1]

passed = list(filter(is_pass, students))
print([name_of(s) for s in passed]) # ['Tom', 'Ann', 'Bob', 'Amy']

by_score = sorted(students, key=score_of, reverse=True)
print([name_of(s) for s in by_score]) # ['Ann', 'Amy', 'Tom', 'Bob']

total = sum(map(score_of, students))
print(total) # 339

拆开之后,每个函数的意图都一目了然;想改"及格线",只要动is_pass一处。 这比只写一个几十行的大函数要可靠得多。


七、工具对照表




工具返回惰性备注



map(func, it)迭代器是需list()取结果

filter(func, it)迭代器是需list()取结果

sorted(it, key=...)新列表否不改原对象

list.sort()None—原地排序

reduce(f, it[, init])单个值否需从functools导入

all/any布尔短路不遍历完



常见坑点



  1. 以为 map / filter 返回列表


``python # ❌ 直接取值会得到迭代器对象 m = map(str, [1, 2]) print(m) # <map object ...> # ✅ 需要列表就转一下 print(list(map(str, [1, 2])))``



  1. 迭代器被消费两次


``python m = map(str, [1, 2, 3]) # ❌ 第一次遍历后迭代器已耗尽 for x in m: pass print(list(m)) # [] # ✅ 先物化成列表再复用 items = list(m)``



  1. 把 sort 的返回值当排序结果


``python data = [3, 1, 2] # ❌ sort 原地排序并返回 None result = data.sort() # ✅ 要么直接用 data,要么用 sorted result = sorted(data)``



  1. lambda 里塞语句


``python # ❌ lambda 只能是一个表达式,不能有语句 f = lambda x: if x > 0: return x # ✅ 用 def def f(x): if x > 0: return x``



  1. 循环里用 lambda 全取到最后一个值


``python # ❌ 延迟绑定,调用时 i 已是最后一个 funcs = [lambda: i for i in range(3)] print([f() for f in funcs]) # [2, 2, 2] # ✅ 用默认参数固定当前值 funcs = [lambda i=i: i for i in range(3)] print([f() for f in funcs]) # [0, 1, 2]``



  1. 忘了导入 reduce


``python # ❌ NameError:3 里 reduce 不再是内置的 reduce(lambda a, b: a + b, [1, 2]) # ✅ 从 functools 导入 from functools import reduce``



  1. 对空序列用 reduce 且没给初始值


``python from functools import reduce # ❌ 空序列 + 无初始值 → TypeError reduce(lambda a, b: a + b, []) # ✅ 给一个初始值 reduce(lambda a, b: a + b, [], 0)``


总结




想做的事推荐写法



一次性小函数lambda,且只写表达式

命名清晰的小函数def,一行看完

逐元素变换 / 筛选推导式优先,map/filter次之

排序依据sorted(key=...),注意返回新列表

累积归约functools.reduce,记得导入

全真 / 存在all/any,且会短路



"大话题"之所以能落到"小函数",关键是两件事:每个函数只做一件事,以及把函数当成值交给通用工具去组合。记住map/filter返回的是只消费一次 的迭代器,就能避开最常见的那几个坑。




版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 3:00:57

电缆温度场仿真在电力传输中的关键应用与COMSOL实践

1. 电缆温度场仿真的工业价值与核心挑战在电力传输领域&#xff0c;电缆温度控制从来都不是一个简单的技术参数问题。去年某沿海城市地铁供电系统的一次故障排查经历让我深刻认识到这一点——由于隧道内电缆沟散热设计缺陷&#xff0c;夏季高温时段多条10kV电缆长期处于临界温度…

作者头像 李华
网站建设 2026/10/30 3:00:50

JavaEE期末题库结构化:知识点树、组卷抽题与掌握度

简介&#xff1a;《JavaEE期末复习题库》面向准备JavaEE课程期末考核的高校学生与需要梳理MyBatis基础知识的自学者&#xff0c;聚焦MyBatis配置元素、SQL映射、ORM理解与工作原理等高频考点。压缩包内共1个docx文件&#xff0c;约41KB&#xff0c;按章节组织填空题、判断题、选…

作者头像 李华
网站建设 2026/10/30 3:00:06

C#两次编译机制解析:从MSIL到JIT的底层原理与避坑指南

简介&#xff1a;这份PPT教程面向零基础或希望系统梳理C#与.NET知识体系的初学者&#xff0c;围绕C#语言基础与面向对象设计展开&#xff0c;帮助读者理解.NET Framework的整体架构与代码编译运行机制。内容从C#语言由来与特点讲起&#xff0c;涵盖程序基本结构、类与命名空间、…

作者头像 李华
网站建设 2026/10/30 2:59:26

APP官网模板实战:从零搭建到上线部署的完整指南

简介&#xff1a;这份资源是面向移动端网页开发初学者与前端基础薄弱团队的一套手机网站HTML模板&#xff0c;围绕APP应用场景提供可直接套用的页面骨架&#xff0c;帮助解决从零搭建移动站点时结构混乱、适配困难的问题。压缩包共39个文件&#xff0c;约215KB&#xff0c;以22…

作者头像 李华
网站建设 2026/10/30 2:59:04

仓储数字孪生:三维重构与空间认知技术解析

1. 项目背景与核心价值仓储三维空间重构与结构认知系统&#xff0c;本质上是通过视频反演技术实现物理仓库的数字化镜像。这个领域最近两年在工业界快速升温&#xff0c;我们团队在实际落地某跨国物流企业的华东枢纽仓时&#xff0c;发现传统仓储管理存在三个致命痛点&#xff…

作者头像 李华
网站建设 2026/10/30 2:58:28

OpenClaw:开源AGI基础设施与智能体开发实战

1. OpenClaw项目概述&#xff1a;AGI基础设施的破局者OpenClaw作为2026年最具颠覆性的开源AGI基础设施项目&#xff0c;正在重塑智能体开发范式。这个以"龙爪"命名的平台本质上是一个模型无关的智能体操作系统&#xff0c;其核心设计理念可概括为"三不原则"…

作者头像 李华