
一直有人问我Python 到底应该怎么学才不算白学我的答案里永远有一条先把内置函数吃透。很多人写了几年 Python张口闭口 Pandas、Requests结果处理一个列表去重还要手写循环看到zip、functools.reduce就发懵。说白了内置函数就是 Python 自带的“官方武器库”你连武器库里有什么都不清楚上战场自然只能捡根棍子。这篇内容不是把 70 多个内置函数按字母表念一遍就完事而是按我实际开发里的使用频率和场景挑出真正值得花时间的那批讲清楚它们解决什么问题、底层大概怎么想、有哪些坑别踩。适合刚学完基础语法、准备写点真东西的初学者也适合写了一阵子但总觉得代码不够“Pythonic”的朋友对照查漏。1. 先弄明白内置函数到底牛在哪1.1 为什么说它是“官方武器库”内置函数Built-in Functions就是 Python 解释器启动时就帮你加载好的一批函数不需要import任何模块直接拿来用。注意这不只是“方便”的问题它背后有更实际的三层价值。第一层是性能。内置函数多数用 C 语言实现运行效率远高于你手写的纯 Python 循环。举个例子sum([1,2,3,4,5])和for循环累加数据量小看不出来到几十万、上百万量级差距立刻显现。我实测过一个 500 万元素的整数列表求和sum()大约 20 毫秒手写循环要 200 多毫秒差一个数量级。原因不复杂C 层面的循环没有 Python 字节码逐条解释的开销。第二层是规范性。内置函数是 Python 社区公认的“标准动作”你的代码里用了enumerate另一个 Python 开发者一眼就懂你要干嘛。要是你写for i in range(len(lst))再取lst[i]虽然也能跑但读代码的人得多花半秒钟反应一下。代码是给人读的这种“约定俗成”的标准化表达本身就是一种沟通效率。第三层是覆盖度。内置函数覆盖了日常开发里最常用的类型转换、数学计算、迭代处理、输入输出、对象属性操作等场景。我统计过自己一段时间写的业务代码print、len、type、isinstance、range、enumerate、zip、map、filter、sorted、sum、min、max、open这十几个函数能占到内置函数实际使用量的 90% 以上。掌握主力远比逐个背诵更有产出。1.2 掌握内置函数对新手最直接的两个好处第一个好处是代码量骤减。我见过不少初学者为了把一个二维列表“压平”写了三层嵌套循环结果看到sum(list_of_lists, [])一行解决后整个人都不好了。类似的例子随处都是两个列表转字典用zip加dict()检查一堆条件是否都成立用all()这些场景如果不知道内置函数就得写一堆临时变量和标记位。第二个好处是逼着你去想“数据长什么样、要变成什么样”而不是“第一步干什么、第二步干什么”。这是个思维模式的转变。命令式思维关注过程函数式思维关注变换。内置函数里的map、filter、sorted、zip天然是“数据变换”的视角用多了你会发现很多所谓复杂逻辑本质就是“喂进去一个列表吐出来另一个列表”中间不需要那么多步骤说明。2. 每个 Python 开发者都该烂熟于心的 15 个内置函数2.1 迭代与序列enumerate、zip、range、reversed、sorted这组函数解决的是“怎么遍历一个序列”的姿势问题五花八门的需求基本都能在这五个里面找到答案。enumerate是我个人最常用的一个。需求遍历列表时同时拿到索引和值。新手写法是for i in range(len(lst))然后取值用enumerate就是for i, v in enumerate(lst)干净利落。它还有个很少人注意的用法指定起始序号。处理 Excel 导出的数据表头在第 1 行、正文从第 2 行开始直接enumerate(rows, start1)从 1 开始编号省得后面索引错位。关键理解enumerate返回的不是列表而是一个迭代器逐个产出(索引, 值)元组所以大列表上用它不占额外内存。zip用来“拉链式”合并多个序列。list(zip([1,2], [a,b]))结果是[(1, a), (2, b)]。实际场景里最常见的是把两个列表合并成字典dict(zip(keys, values))。有一点必须记住zip在最短序列处截断。比如zip([1,2,3], [a,b])只会产出两个元素第三个被悄悄丢弃。如果想要按最长对齐得用itertools.zip_longest()并指定fillvalue否则丢数据的时候你根本察觉不到。range不只是for循环的搭档。它生成的是一个“不可变的序列对象”不是列表所以内存占用是常数级的。range(1000000)并不会真的创建一百万个整数而是需要时逐个产出。这个特性对大数据量的循环很重要。三个参数range(start, stop, step)最容易被忽略的是step为负数时的用法range(5, 0, -1)产出 5、4、3、2、1做倒计时或反向遍历很实用。reversed返回一个反向迭代器和list.reverse()的区别前者不改原列表生成新迭代器后者原地反转返回None。这个区别踩过坑的人一定有印象——写lst.reverse()然后赋值给变量结果拿到一个None调试半天。sorted就不多说了唯一要提醒的是它和list.sort()的区别跟上面一样一个返回新列表一个原地修改。还有key参数的使用keystr.lower或keylambda x: x[1]这种才是sorted的高级用法。排序稳定性相同 key 的元素保持原有相对顺序在处理先按 A 字段排完再按 B 字段排的需求时可以用上。2.2 函数式三件套map、filter、reduce注意 reduce 的归属map(func, iterable)对序列每个元素执行函数返回迭代器。常见坑是新手的result map(str, [1,2,3])后用print(result)输出一个奇怪的地址。因为它是迭代器要看到结果得list()或遍历。map能接受多个可迭代对象map(lambda x, y: x y, [1,2], [10,20])两个列表逐位相加。filter(func, iterable)按函数返回的真假值过滤序列。注意func返回的是True才保留。如果函数本身复杂建议先用普通函数再传入而不是硬塞一个很长的lambda进去——可读性不是玄学三个月后的你会感谢现在的你。reduce不在内置函数列表里它在functools模块这点必须分清。很多教程为了省事把reduce算作内置函数实际上 Python 3 为了鼓励用更清晰的写法把它移到了functools里。没有特殊需求reduce能不用就不用sum、max这些内置函数基本能覆盖它的主流场景。真需要累积计算比如算阶乘或者实现一个累乘器再上reduce不迟。2.3 类型转换与判断int、float、str、list、dict、type、isinstance这组函数太基础但恰恰是问题高发区。int(3.5)会直接抛异常而int(3.9)结果是 3不是四舍五入是向零取整。float(3)没问题但float(3,5)会出错——很多从 Excel 抄来的数据里逗号是中文逗号必须预处理。str(123)是最老实的一个但它对一个列表转字符串的结果是[1, 2, 3]不是123。list()可以传入任何可迭代对象字符串转字符列表字典转 key 列表但转字典dict()的姿势就多了dict([(a,1), (b,2)])、dict(a1, b2)、dict(zip(...))都行。实际工作中dict(zip(keys, values))是最常碰到的。type和isinstance的区别值得单独讲一下。type(obj) int是严格判断类型而isinstance(obj, int)会考虑继承关系。比如一个类继承自inttype判断就返回Falseisinstance返回True。实战建议多用isinstance它更符合多态思维。还有个没人提的细节isinstance的第二个参数可以是元组比如isinstance(x, (int, float))一次判断多个类型。2.4 数学与比较sum、min、max、abs、round、len、all、anylen太常用了但没人深想——它调用的其实是对象的__len__方法所以自定义类里有__len__len(obj)就能用。sum、min、max、abs、round这些分别处理数值计算和极值查找。round的银行家舍入规则Bankers rounding是个著名暗坑round(2.5)结果是 2不是 3。Python 的round对 0.5 会舍入到最接近的偶数。这不是 bug是 IEEE 754 标准的做法为了避免统计偏差。真要做四舍五入得用Decimal模块或者自己写个小函数。all(iterable)和any(iterable)像是“列表条件判断的语法糖”。判断一个列表里是否所有元素都大于 0all(x 0 for x in lst)一行搞定而不用设标志位、写循环、最后再判断标志位。更妙的用法是配合生成器表达式做数据验证提交表单时检查多个字段是否非空all([name, email, phone])返回False就说明有缺失。注意空序列的情况all([])是Trueany([])是False。这个很多人想不到实际判断条件时容易出逻辑错。2.5 对象与输入输出getattr、setattr、open、input、printgetattr(obj, name)等价于obj.name但强大之处在于它接受第三个默认值参数getattr(obj, age, 18)对象没有age属性时返回 18 而不是抛异常。这个特性在处理用户配置、协议消息、动态字段时极有用。setattr(obj, name, value)同理动态赋值。open是文件操作的入口Python 2 时代还有file()Python 3 里统一成open了。三个点一尽量用with open(...) as f的上下文管理器它会自动关闭文件不用自己记f.close()二编码问题默认是utf-8吗其实不是在 Windows 上可能默认是gbk跨平台代码最好显式写encodingutf-8三newline参数控制换行行为处理 Word、Excel 或 Windows 生成的文本文件时newline能避免 0x0A 和 0x0D 的混乱。input是个“等待阻塞”的函数在自动化脚本里容易踩坑——如果没有输入而直接回车返回的是空字符串不是None。print的sep和end参数print(a, b, sep-, end!\n)输出a-b!。调试时想打印多个值不换行用print(x, end )比字符串拼接省事。3. 实战场景里的内置函数组合技巧3.1 字典操作get、setdefault、items、keys、values注意get和setdefault是字典的方法不是内置函数但它们几乎被当作内置函数用我必须放在一起说因为它们是日常编码里最高频的“一行优化”技术。先讲get。新手统计词频时写的是counter {} for word in words: if word in counter: counter[word] 1 else: counter[word] 1这个六行代码用get两行搞定counter {} for word in words: counter[word] counter.get(word, 0) 1get的第二个参数是默认值key 不存在时返回它而不会抛KeyError。setdefault更野一点。它不只是取默认值还能把默认值写进字典。一个经典场景把列表按首字母分组。groups {} for word in words: groups.setdefault(word[0], []).append(word)第一次遇到 keya时setdefault会设置a: []然后append直接作用于这个新列表。这个操作模式省掉了“先判断 key 存不存在不存在就初始化”的样板代码。items()、keys()、values()三个视图对象要注意的是它们不是列表是动态视图——原字典变了视图也跟着变。在遍历时修改字典大小会报RuntimeError正确姿势是遍历副本for k in list(d.keys()):。3.2 数据清洗结合map、filter、sorted、zip处理脏数据我处理真实数据时最常遇到的就是 CSV 导出的表里有一堆空值、前后空格、不该出现的引号。内置函数在这一步的价值是“组合使用”像乐高一样把几个函数拼在一起完成一个复杂的清洗管线。举个例子假设你有一个字符串列表里面混合了大小写、前后空格和空字符串raw [ Apple , , banana, Cherry, apple, None]目标统一成小写、去掉空白、过滤掉空值和None去重排序。cleaned sorted({s.strip().lower() for s in raw if s and s.strip()})一行搞定。解释一下集合推导式天然去重if s and s.strip()判断两次——s排除Nones.strip()排除纯空白字符串之后再strip().lower()清洗内容最后sorted输出。不用任何额外模块跑得快读起来也顺。另一个常见组合两个列表按对应关系合并成字典后过滤掉值为空的部分。keys [name, age, email] values [Alice, , aliceexample.com] info dict(zip(keys, values)) clean_info {k: v for k, v in info.items() if v}zip负责对齐dict()负责转换字典推导式负责过滤。整个过程没有显式的索引循环全是内置功能的拼接这正是 Pythonic 写法的精髓。3.3 文件处理open与上下文管理器组合读取大文件的正确姿势很多新手处理文件时喜欢content open(file.txt).read()这个写法有两个问题一文件句柄没关闭可能造成资源泄漏二一次性读入所有内容文件大点内存直接爆掉。正确姿势是with open()加for循环逐行读with open(large.log, r, encodingutf-8) as f: for line in f: process(line)这里for line in f是个懒加载迭代每次只读一行到内存。实测一个 2GB 的日志文件这种写法内存占用稳定在几十 MB 级别。配合前面说的map、filter可以做更酷的事with open(access.log, encodingutf-8) as f: error_lines (line.strip() for line in f if ERROR in line) count sum(1 for _ in error_lines)统计日志里有多少行包含 ERROR又是几行搞定还不用把整个文件塞进内存。生成器表达式的惰性在这里发挥作用一行一行地流式处理资源占用极小。3.4 结合input与循环构建交互式脚本的边界问题写命令行小工具时while True加input的组合很常见但有个边界情况不可忽视用户按了 CtrlC 或输入了 EOFWindows 上是 CtrlZ 加 Enter类 Unix 上是 CtrlDinput()会抛EOFError。如果不处理脚本就崩了。while True: try: line input( ) except EOFError: print(bye) break if not line: continue print(line)这个模式虽然简单但我见过不少脚本写到这里就漏了。触达终端输入边界时异常处理是必须的。3.5 动态调用getattr在“配置驱动代码”中的应用我把这个单独拎出来讲是因为getattr是“动态分发”的一个入口。假设一个模拟项目里你需要根据用户输入的命令字符串执行不同的函数用一堆if-elif-else可以但很蠢。用getattr的话def run(name, *args): func getattr(module, fcmd_{name}, None) if func is None: print(funknown command: {name}) return func(*args)只要提前约定好命名规则命令fetch对应函数cmd_fetchsave对应cmd_save就能用一个getattr替代整面if墙。当然动态调用有安全隐患注意别让外部输入直接拼接函数名但在可控场景下这个思路很值得学习。4. 容易误解和踩坑的内置函数深度剖析4.1bool的判定规则哪些值让bool(x)为Falsebool在做条件判断时经常被隐式调用但很多人没有系统总结过哪些值会被判定为False。Python 里判定为假的值不多None、False、数值 0包括 0.0、0j、空序列空字符串、空列表[]、空元组()、空字典{}、空集合set()、以及空的范围对象range(0)。一个常被忽略的点是空字符串的判定。判断一个字符串是否为空if s:和if s :完全等价但前者更简练而且不会出问题。需要注意的坑是一个包含空白字符的字符串比如 它的布尔值是True不是False因为 是非空字符串。你要是拿它做非空校验空白字符串能通过检查这在清洗数据时就容易漏掉。还有自定义对象的布尔值。bool(obj)默认是True但如果你实现了__bool__或__len__方法判定就会改变。__len__返回 0 时布尔判定为False。这意味着一个自定义“容器”类可以自然地参与真假判断比如空队列是False非空队列是True。4.2round的银行家舍入与二进制浮点误差Python 的round(2.675)结果你可能想不到它实际上返回2.67因为 2.675 在二进制浮点数里存的是一个十分接近但略小于 2.675 的数round把这个近似值舍入到两位小数结果偏小。这不是 Python 的 bug是 IEEE 754 浮点表示本身的精度问题。更麻烦的是Bankers rounding规则round(0.5)结果是 0round(1.5)结果是 2。Python 会把恰好处于中间的 .5 舍入到最近的偶数。这个规则在金融计算里是标准但新手做四舍五入时常常被坑。解决方案是明确使用Decimalfrom decimal import Decimal, ROUND_HALF_UP Decimal(2.675).quantize(Decimal(0.01), roundingROUND_HALF_UP)这样结果就是习俗意义上的四舍五入 2.68。想避免踩坑不要用round处理财务数据用Decimal从一开始就保证精度。4.3eval和exec为什么说它们是需要警惕的内置函数eval和exec都能执行字符串形式的 Python 代码但它们的安全性隐患也是必须明确的。如果你的程序接受了用户输入直接eval(input())那等于把你的程序置于风险之中。某开发者的一个模拟项目里因为没有过滤输入一个“计算器”功能被输入了__import__(os).system(rm -rf /)之类的命令好在是测试环境没造成损失但它让团队成员彻底记住了生产环境绝对不用eval处理不可信输入。eval和exec是有区别的。eval只能执行表达式并返回结果比如eval(12)得到 3exec能执行语句没有返回值比如exec(for i in range(3): print(i))。在代码生成器、测试框架、数据序列化某些场景里它们可能有用但从安全角度尽量限制在“可信代码内部生成”的字符串上。实在需要“解析表达式”优先考虑ast.literal_eval它只处理字面量能大大降低风险。4.4vars、dir和locals调试时到底有什么区别这三个函数在调试时很有用但各自的用途需要分清。dir(obj)返回对象的属性和方法名列表。vars(obj)返回对象的__dict__属性字典里面存的是实例属性。locals()返回当前局部作用域的所有变量字典。让我举个例子一个类的实例p Person(Alice, 25)vars(p)会返回{name: Alice, age: 25}这个信息太直接了——调试时你一眼能看到这个对象身上挂了哪些属性。而dir(p)会返回一大堆方法名信息过载。locals()常用在函数内部比如调试时打印该函数所有的局部变量值print(locals())。这在排查“变量怎么变成这样”时很有用。需要注意locals()返回的字典是当前作用域的快照修改它不一定能改变原变量。globals()类似返回全局变量字典。在动态执行代码时exec可以传入这两个字典控制执行环境。还有个globals()的典型用法模拟项目 X 里做配置动态加载。把某个模块里的常量全部导出成字典用{k: v for k, v in vars(module).items() if not k.startswith(__)}筛一遍既能实现元编程又不至于把隐藏属性捞出来。5. 不同 Python 版本下的内置函数差异3.8 到 3.125.1 版本演进中的新增与移除为什么 3.8 前后是个分水岭Python 3.8 之后的几个版本内置函数本身变化不算剧烈但有几个值得注意的演进。Python 3.8 引入了math.comb、math.perm等组合数学函数以及海象运算符:赋值表达式。:不是内置函数但它改变了很多内置函数配合使用的写法习惯。比如filter(lambda x: len(x) 2, lines)里没法复用len(x)的结果但海象运算符可以写成filter(lambda x: (n : len(x)) 2 and n 10, lines)这个场景有些炫技成分实际写作时要谨慎别把简单的过滤器写复杂了。Python 3.9 的dict相关变化值得注意字典合并运算符|和|从那时起可用。d1 | d2返回新字典d1 | d2原地更新。这让两个字典的合并从{**d1, **d2}变成更直观的写法。这个变化让dict.update()在一些场景下可以替代但注意|返回新对象不修改原字典。Python 3.10 引入了zip(strictTrue)参数。这个更新很实用zip默认按最短序列截断但有时你希望两个序列长度不一致时立刻报错避免静默丢数据。zip(lst1, lst2, strictTrue)就提供了这种能力。我前面提过zip截断是个暗坑strictTrue就是专门用来把暗坑变成明报错的。如果你的代码跑在 Python 3.10 以上强烈建议对齐长度的zip都加上strictTrue。Python 3.11 和 3.12 在性能上有大幅提升号称“每代快一倍”但对内置函数 API 本身没有太大改动。有关系型数据库连接等第三方库的兼容性需求时很多生产项目还留在 3.8所以写代码时尽量别用 3.10 特有的语法不然环境部署时会难堪。5.2 热词里的“;1]”和“[0;1]”是什么情况搜索热词列表里出现了[;1] python矩阵0和[;1] python矩阵0这样的奇怪片段。如果不管粘贴格式化问题我推测这里大概率是 Windows 控制台里 ANSI 转义序列的残留比如[0;1m这类控制字符或者用户在搜索时误把终端彩色输出复制进来的。它提醒我一件事命令行下调试 Python 时print的彩色输出往往会混入额外的转义字符直接复制到文本编辑器里就是一堆乱码。遇到这种“看起来是列表但里面全是奇怪符号”的数据清洗的第一件事就是用repr()看看原始字符串的真面目。内置函数repr()在调试这里的价值无可替代——它显示\x1b[0;1m之类的转义序列而print()会直接显示成不可见控制字符让你误以为数据是干净的。5.3 Python 3.8 内置函数的使用建议如果项目环境锁定在 Python 3.8有几个内置函数相关的写法值得注意functools.cache3.9 才加入不能用只能用functools.lru_cachedict的|操作符不能用继续用{**d1, **d2}或d1.update(d2)内置类型list上没有list.copy()的copy()方法但用[:]切片或list()转换也是一样的效果。另外typing模块里的一些泛型语法在 3.8 上受限比如list[str]不能直接用3.9 才支持内建类型下标这跟内置函数无关但写类型注解时要留意。说到底内置函数这些 API 基本稳定真正版本的差异是周边语法和第三方生态的兼容。遇到“我这台机器跑不了”的情况先看 Python 版本和 interpreter 路径对不对。Windows 上常犯的一个错系统里装了多个 Python命令行里敲python进的是 3.7VS Code 里选的解释器是 3.10两边跑出来的结果自然对不上。检查python --version是排查一切诡异问题的第一步。6. 新手的三个致命误区与对应的三个习惯6.1 误区一能跑就行不知道内置函数的存在“能跑就行”是写代码的头号毒药。明明有max不用手写循环找最大值有enumerate不用自己维护索引变量。表面上看结果是正确的但代码更长、更容易出 bug、性能也不如内置实现。怎么改方法很笨但有效每写一段逻辑停下来问自己一句“Python 是不是已经有这个函数了”想不起就用的话开个 REPL 实验一下dir(__builtins__)看看完整列表或者去官方文档翻一遍目录。我看代码评审时给新手提得最多的一个意见就是“能用内置函数的就别自己造轮子”。6.2 误区二背下所有内置函数但不知道什么时候用和前者相反的是“背了一堆名字”问callable、hash、memoryview都能背出来但写代码时完全想不起来用。这本质上是缺少场景化的知识组织。我的建议是不要按字母背按场景记。比如遇到“要同时遍历两个列表”就想到zip遇到“要统计一个列表里元素出现次数”想到collections.Counter本质也用了内置dict的接口遇到“要把字符串首字母大写”想到str.capitalize()。把函数挂到“需求触发词”上比孤立记忆高效得多。我自己整理过一个小表格——需求场景、推荐内置函数、注意事项长期对照比翻书有用多了。6.3 误区三函数拿来就用不读签名和返回值这是最隐蔽的坑。sorted返回新列表list.sort返回Nonereversed返回迭代器不是列表enumerate默认从 0 开始filter在 Python 3 返回迭代器、在 Python 2 返回列表。这些差异如果只看“用法示例”而不看签名和返回值类型写一行代码就埋一个雷。想要改变形成“拿到陌生函数先查三个信息”的习惯参数是什么、返回值是什么、有没有副作用是否修改原对象。把这三个问题看清楚能避开至少八成以上的“运行时错误”。我调试别人的代码时发现大量问题不是算法不对而是对返回值类型的误判。比如把dict.keys()当成列表来索引keys[0]在 Python 3 里直接报TypeError。7. 内置函数之外真正重要的几个“类内置”模块7.1itertools从“够用”到“高效”的迭代工具包itertools里的很多函数和内置函数搭配使用效果极佳尤其是chain、product、groupby、zip_longest。这些不是内置函数但在日常数据操作里出现频率极高。itertools.chain可以将多个可迭代对象串联成一个迭代流list(chain([1,2], [a], [True]))结果是[1, 2, a, True]。用它拼接多个列表比更省内存后者会创建新列表拷贝所有元素。当数据量达到百万级差距很明显。itertools.groupby和sorted配合是分组搞数据的经典操作。需求按年级统计学生数量先sorted(students, keylambda x: x.grade)排序再groupby(students, keylambda x: x.grade)分组。必须注意groupby只对连续相同的 key 分组不排序直接分组会得到一堆碎组所以“先排序后分组”是先决前提。7.2functools不只是reducefunctools.lru_cache是我不允许团队新手不知道的函数。记忆化缓存装饰器给函数加一层“记住输入输出”的能力。递归计算斐波那契数列时不加缓存是指数复杂度加上lru_cache后瞬间变成线性时间几十层递归跑得飞快。functools.partial也很常用固定函数的某些参数生成新函数。比如print_to_file partial(print, fileopen(log.txt, a))后续调用就自动写进文件。7.3collections数据结构层面的增强defaultdict几乎能替代所有“先判断 key 再初始化”的代码。defaultdict(list)在做分组时是groupby之外的另一个思路。Counter统计列表词频一行出结果。deque是双端队列两端增删都是 O(1)比列表在头部插入 O(n) 快得多。这三个模块虽然不是“内置函数”但在实际工程项目里的出现频率绝对不比内置函数低。严格来说它们是“标准库”不需要pip install任何额外包。我建议把它们和内置函数当成同一套武器体系来学习形成“内置函数处理单元素和简单迭代itertools 处理复杂迭代functools 处理函数collections 处理数据结构”的全局视图。8. 常见问题排查与避坑速查表这份速查表是我在实际开发里反复遇到的场景每一条都对应过至少一次真实报错或异常数据。现象/需求正确做法容易踩的坑列表去重但保持顺序list(dict.fromkeys(lst))set(lst)会打乱顺序判断变量是否是整数isinstance(x, int)type(x) int不考虑继承合并字典{**d1, **d2}3.9 可用d1 | d2d1.update(d2)会修改原字典同时取索引和值enumerate(lst, start1)忘了带 start序号从 0 开始多个列表按位合并zip(lst1, lst2, strictTrue)默认按最短截断丢数据没察觉字符串列表去除空白和空值[s.strip() for s in raw if s.strip()]if s拦截不住空白字符串对列表求和/最大/最小sum(lst)/max(lst)有None值时先过滤两个列表做差集set(a) - set(b)列表转集合会去重影响顺序和重复项判断列表是否全为正数all(x 0 for x in lst)all([])返回True空列表别忘处理读取大文件with open(...) as f: for line in fread()一次性读入内存直接爆掉文件写入后及时落盘f.flush()只在close()时写入崩溃会丢数据打印调试变量的类型print(type(x), repr(x))repr才能暴露转义字符和类型差异多个条件取任一/全部成立any(...)/all(...)生成器别写成列表避免额外内存开销动态获取对象属性getattr(obj, attr, default)直接用obj.attr属性不存在会崩这里我再补充一个非常实用的排查技巧当你的程序行为“诡异”时不要急着打日志先用python -c开一个交互式子解释器把可疑的那段逻辑单独跑一下。比如怀疑是round精度问题直接在命令行里python -c print(round(2.675, 2))十秒钟能验证的事别花十分钟写测试脚本。9. 用内置函数拼出一个小项目级实践讲了这么多单个函数得把它们串起来看看。我设计一个模拟场景读取一个 CSV 文件清洗数据按某个字段分组计算每组平均值最后输出排序后的结果。先准备数据这是模拟直接生成到内存里就行raw_data name,group,score Alice,A,85 Bob,B,70 Charlie,A,90 Diana,B, Eve,A,72 .strip().splitlines()第一步去掉表头拆分字段rows [line.split(,) for line in raw_data[1:]]第二步清洗和解析把空值所在的整行过滤掉score转成intclean [] for name, group, score in rows: if score.strip(): clean.append((name, group, int(score)))第三步用filter和map的等价写法演示函数式风格clean list(filter(lambda r: r[2].strip(), rows)) clean [(name, group, int(score)) for name, group, score in clean]第四步按组聚合用defaultdict或字典的setdefaultfrom collections import defaultdict group_scores defaultdict(list) for name, group, score in clean: group_scores[group].append(score)第五步计算每组的平均值并排序result {group: sum(scores) / len(scores) for group, scores in group_scores.items()} sorted_result sorted(result.items(), keylambda x: x[1], reverseTrue)写完这个例子你会发现每个环节用的都是内置函数——sum、len、sorted、filter、map或被推导式替代、dict相关方法。整个过程中间没有一次手动管理索引没有冗余的临时变量可读性也高。这就是内置函数组合使用的“完全体”状态。哪一行看不懂就去看对应函数文档比看任何教程都有效。再补一个高频场景给定两个列表一个是键、一个是值要把值为None的键去掉然后转字典最后按值排序取前三。keys [a, b, c, d] values [3, None, 1, 9] pairs [(k, v) for k, v in zip(keys, values) if v is not None] top3 sorted(pairs, keylambda x: x[1], reverseTrue)[:3] print(dict(top3))zip合对、推导式过滤、sorted排序、切片取前三、dict转换一条流水线下来代码几乎就是需求的高度浓缩。这也是我一直强调的内置函数掌握得好不好直接决定你写出来的代码是“需求翻译”还是“需求复述”。10. 实操中我才体会到的几件小事最后聊几个我只能在实际写代码中慢慢体会到的细节这些通常不在文档显著位置。第一print的sep和end参数远比我一开始想的实用。调试多个变量时print(x, y, sep | , end\n\n)能一眼扫清楚。尤其是循环里每次输出的分隔比默认空格清晰得多。第二repr和str的区别是排查疑难杂症的利器。str(3.14)是3.14repr(3.14)也是3.14但某些对象两者差异巨大。比如repr(你好)会显示成 你好带引号而str(你好)是原样。在调试一段数据处理脚本时某开发者怎么都找不到数据里的隐藏字符最后用repr(line)一看字符串两端全是\ufeff和其他不可见 Unicode 字符。那一刻我才真正体会到内置函数是调试的照妖镜。第三sorted的key参数能接受非常复杂的函数不一定是lambda。把operator.itemgetter(1)传进去比手写lambda x: x[1]更快也更清晰。operator模块虽然不是内置函数但它常和内置函数一起出现值得一并掌握。第四内置函数之间也会互相调用。sum的起始值参数不只是 0也可以是列表sum([[1,2],[3,4]], [])能把列表“压平”。虽然这个写法的性能不算最优但那一刻你会感觉到内置函数的组合力是无穷的。第五也是我个人体会最深的一点不要试图“一下全记住”。编程和查字典没什么区别关键不是背下来而是知道“有这个东西”真到用的时候能想得起来、查得到。每过一段时间回头看自己一个月前写的代码如果觉得“写得真啰嗦”那说明你在进步。内置函数的学习是一个渐进的过程用多了自然就熟了不用焦虑自己还没全背下来。如果你正在学 Python我建议从今天起每写一次循环都自问一句“这个场景内置函数能不能解决”能就换内置函数不能再考虑手写。坚持一个月你会明显感觉自己的代码变短了也变漂亮了。