Python内置函数高效使用指南:从入门到实战优化
1. 先从“不用import”这三个字聊起如果你去翻Python官方文档会看到这么一句介绍——“内置函数是Python解释器内置的一系列函数可以直接使用无需导入任何模块。”看起来挺清淡的但这句话背后信息量不小。我见过很多初学者写代码的一个典型状态打开编辑器先敲一行import math才敢用math.sqrt()碰到datetime要导包、碰到random要导包、碰到json要导包。久了以后会形成一种惯性——“要用别人写好的工具就得先导入”。实际上Python内置了七十多个函数直接就可以调用你甚至不需要做任何导入操作。它们深藏在解释器底层几乎每个Python程序运行的时候这些函数都已经就位了。abs()、all()、any()、bin()、bool()、bytes()、callable()、chr()、complex()、dict()、divmod()、enumerate()、eval()、exec()、filter()、float()、format()、frozenset()、getattr()、globals()、hasattr()、hash()、help()、hex()、id()、input()、int()、isinstance()、issubclass()、iter()、len()、list()、locals()、map()、max()、memoryview()、min()、next()、object()、oct()、open()、ord()、pow()、print()、property()、range()、repr()、reversed()、round()、set()、setattr()、slice()、sorted()、staticmethod()、str()、sum()、super()、tuple()、type()、vars()、zip()……列出来一大串但真正在每天写代码里高频出现、且能显著提升效率的其实也就二三十个。这篇文章我想把这些内置函数的用法按“场景”而不是按“字母表”重新梳理一遍。网上很多教程习惯一条一条罗列看完记住了名字遇到实际问题还是不知道该用哪个。我写代码这些年最大的体会是内置函数不是用来背的是用来“解题”的。你手头有个需求知道哪个内置函数能直接给你答案这才叫掌握了它们。先说明白这篇文章适合谁刚学Python不久、写练习题能写但对内置函数没什么整体概念的新手以及写过一段时间代码想看看自己有没有“绕远路”的读者。老手也可以翻翻说不定有几个函数你压根没注意过。2. 整体设计思路我是怎么把这些函数重新归类的2.1 为什么按使用场景分组Python文档里内置函数就是按字母顺序排的——abs到zip一共七十多个。这种排列方式方便查询但不利于学习。就像你手里有一本字典按拼音排好了每一个字可你想学“怎么写一封得体的邮件”翻字典是没用的你需要的是“这些字怎么组合起来表达一个意思”。我倾向于把内置函数按“它们到底在解决哪类问题”来分组。仔细捋一遍其实大部分内置函数都逃不出这六个场景数值处理对数字做运算、取整、进制转换、绝对值等。代表选手abs()、round()、divmod()、pow()、sum()、min()、max()、oct()、hex()、bin()。类型转换与判断在不同数据类型之间切换或者判断一个对象是不是某种类型。代表选手int()、float()、str()、list()、tuple()、set()、dict()、isinstance()、type()。序列与迭代操作这是内置函数里最“值钱”的一块。处理列表、元组、字典、字符串做过滤、映射、排序、枚举、聚合。代表选手enumerate()、zip()、map()、filter()、sorted()、reversed()、all()、any()、range()。对象属性与反射动态地获取对象的属性、判断对象能不能被调用等。代表选手getattr()、setattr()、hasattr()、callable()、id()、hash()。输入输出与交互控制台读入、打印、打开文件。代表选手print()、input()、open()。代码执行与动态求值把字符串当代码跑起来或者在内置命名空间里做点“高级操作”。代表选手eval()、exec()、globals()、locals()。这么一分你想解决什么问题就直接到对应的“工具区”去找比挨个背轻松多了。2.2 内置函数为什么快很多人有一个误区觉得“内置函数就是个普通函数无非是Python官方帮忙写好、免去了import而已”。这个理解不准确。内置函数的执行效率通常比你手写的等效代码高得多原因在于它们大多是在C语言层面实现的。Python本身是解释执行的语言你写一个for循环去累加一万个数字解释器要一条一条把字节码翻译成操作而sum()直接调底层C实现在内存里高效地完成加法循环性能差距非常明显。选内置函数不仅是图省事更重要的是图效率。能用一句内置函数解决的事就别写十行手撕代码——这才是写Python的正道。2.3 内置函数的“边界感”需要特别提一句的是内置函数虽好但也不是万能的。它们只覆盖那些“高频、通用、不依赖具体业务场景”的操作。一旦你的需求涉及到专业领域——比如正则匹配要用re、日期计算要用datetime、数学运算要处理对数三角函数就用math——该导入模块还得导入。所以我的建议是写代码之前先想三秒——“这是不是一类通用操作如果是Python内置函数可能已经有现成的了。”这三秒钟的习惯长期下来能帮你省下大量手写轮子的时间。3. 核心细节解析高频内置函数的正确打开方式3.1 数值计算组别再用循环求最大值了先看代码# 求三个数里的最大值 a, b, c 3, 7, 5 # 新手写法 if a b: if a c: max_value a else: max_value c else: if b c: max_value b else: max_value c # 内置函数写法 max_value max(a, b, c)min()和max()接受多个参数也接受一个可迭代对象简洁很多。但有几个细节容易踩坑第一个坑max()处理空序列。# 假设某个列表可能是空的 my_list [] # 直接max()会报错ValueError: max() arg is an empty sequence # 解决办法设置default参数 max_value max(my_list, default0) # 返回0Python 3.4以上版本支持default参数空序列时返回默认值而不是抛异常。这个点在写健壮代码时很重要。第二个坑round()的银行家舍入。round(2.5)的结果是2不是3。这是Python的round遵循“银行家舍入”四舍六入五取偶规则当小数部分恰好是5时向偶数方向舍入。2.5取整到最近的偶数2是偶数所以结果是2。绝大多数业务场景不会卡在这种边界上但如果你的代码涉及财务金额计算这个坑能让你损失不少钱建议直接用Decimal模块处理金钱不要依赖round()。第三个值得专门讲的函数是divmod()。divmod(a, b)同时返回a // b和a % b两个结果。这个函数在分页场景太常用了。举例total_items 95 page_size 10 # 需要多少页 pages divmod(total_items, page_size) # pages (9, 5)代表9页完整页 1个零头页 total_pages pages[0] (1 if pages[1] else 0)一次拿到整除结果和余数省一次运算代码也更清晰。再看sum()。很多人知道sum()能求和但不知道它能干点更聪明的事。比如把嵌套列表展开一层nested [[1, 2], [3, 4, 5], [6]] flattened sum(nested, []) # 结果是 [1, 2, 3, 4, 5, 6]sum()的第二个参数是起始值。默认是0传入一个空列表[]就能把列表元素逐层相加拼接起来。这算是个小技巧不过要注意这个写法的时间复杂度比直接用列表推导式要差一点数据量大的时候建议用itertools.chain.from_iterable()数据量小的时候用sum()图省事没问题。3.2 类型转换组Python的“变脸”艺术Python是动态类型语言变量不需要声明类型但类型转换无处不在。int()、float()、str()、list()、tuple()、set()、dict()这一组函数熟悉到甚至让人忽略了几个细节。int()的第二个参数是个容易被忽略的功能——按进制转换# 把二进制字符串转成十进制数 binary_str 1010 decimal int(binary_str, 2) # 结果是 10 # 把十六进制字符串转成十进制 hex_str ff decimal int(hex_str, 16) # 结果是 255这个参数在处理协议解析、颜色色号、编码转换时非常实用。比如前端的色号#FF8800你可以这样解析出RGB分量color_hex FF8800 r int(color_hex[0:2], 16) g int(color_hex[2:4], 16) b int(color_hex[4:6], 16) print(r, g, b) # 输出 255 136 0反向操作也有对应函数bin(255)得到0b11111111hex(255)得到0xffoct(8)得到0o10。注意它们会在结果前自动加上0b/0x/0o前缀如果你只需要纯数字部分切片去掉即可。str()在某些场景有惊喜。比如给一个长数字加上千分位分隔符number 1234567890 formatted f{number:,} # 结果是 1,234,567,890虽然这是格式化字符串的功能不是str()本身但str()配合格式化语法在做报表输出时很好用。bool()也值得一提bool(0)是Falsebool()是Falsebool([])是Falsebool(None)是False其余大多数对象都是True。这个“真值判定”规则对写条件判断非常重要。3.3 迭代与序列操作组每天都能省五行的秘密这是内置函数里最值得花时间掌握的部分。enumerate()——遍历列表还要带下标的时候fruits [apple, banana, cherry] # 新手写法 for i in range(len(fruits)): print(i, fruits[i]) # 成熟写法 for i, fruit in enumerate(fruits): print(i, fruit) # 指定起始下标 for i, fruit in enumerate(fruits, start1): print(i, fruit)enumerate()返回一个生成器每次迭代产生一个(索引, 元素)元组。它接受第二个参数start指定索引从几开始。这个函数写遍历场景的频率非常高几乎可以替代range(len())这种写法。zip()——并排遍历多个序列names [Alice, Bob, Charlie] scores [85, 92, 78] # 把两个列表对应位置打包成元组列表 pairs list(zip(names, scores)) # [(Alice, 85), (Bob, 92), (Charlie, 78)] # 同时解包非常优雅 for name, score in zip(names, scores): print(name, score)zip()的经典用法是“转置”二维结构。比如把行数据转成列数据matrix [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] transposed list(zip(*matrix)) # [(1, 4, 7), (2, 5, 8), (3, 6, 9)]zip()在Python 3中返回的是迭代器惰性求值。如果你要多次遍历提前加上list()包一层。另一个细节zip()按最短的序列长度截断。如果你不想截断、而是希望按最长的序列来用itertools.zip_longest()缺失部分用fillvalue填充。map()与filter()——批量操作利器numbers [1, 2, 3, 4, 5, 6] # 把所有数字平方 squared list(map(lambda x: x ** 2, numbers)) # 只保留偶数 evens list(filter(lambda x: x % 2 0, numbers))这两个函数配合lambda使用一行搞定循环加判断的事情。不过Python社区的推荐现在是“列表推导式优先”——[x ** 2 for x in numbers]和[x for x in numbers if x % 2 0]读起来更直观。我的经验是简单的变换与过滤用列表推导式复杂逻辑或函数已定义好的场景用map()和filter()。比如# 假设有一个现成的清洗函数 def clean_name(name): return name.strip().title() raw_names [ alice , BOB, charlie] cleaned list(map(clean_name, raw_names))这种场景用map()比推导式更清晰。sorted()与reversed()——排序的几个不常见用法sorted()不仅能对数字排序还能接受key参数做自定义排序规则。举例words [apple, banana, cherry, date] # 按字符串长度排序 sorted_by_len sorted(words, keylen) # 按最后一个字母排序 sorted_by_last_char sorted(words, keylambda w: w[-1])还有reverseTrue参数控制升序降序。注意sorted()返回新列表原列表不变而list.sort()是原列表原地排序返回None。要排序字典列表key可以指定字典的键students [ {name: Alice, score: 92}, {name: Bob, score: 85}, {name: Charlie, score: 78}, ] # 按成绩从高到低 ranked sorted(students, keylambda s: s[score], reverseTrue)reversed()返回一个反向迭代器不改变原序列text hello reversed_text .join(reversed(text)) # ollehall()与any()——判断一组条件是否全部满足data [1, 2, 3, 4] print(all(x 0 for x in data)) # True print(any(x 3 for x in data)) # True # 验证表单必填字段 fields [form.get(name), form.get(email), form.get(phone)] if all(fields): print(所有字段都已填写)这两个函数直接替代了多条件叠加的if判断链代码瞬间清爽。range()——不止是循环用range严格说是类型不是函数但很多调用方式容易混淆。它支持三个参数range(start, stop, step)。我尤其想提的是倒序循环和步长为负数的用法for i in range(10, 0, -2): print(i) # 10 8 6 4 2注意range是半开区间stop值取不到。range(10, 0, -2)取不到0。这个细节写倒序循环时非常容易错。3.4 反射与对象操作组那些“编程的编程”函数这一组函数平时用得不频繁但在某些场景特别关键。isinstance()和type()的区别# type()严格判断类型isinstance()支持继承关系判断 class Animal: pass class Dog(Animal): pass dog Dog() print(type(dog) Dog) # True print(type(dog) Animal) # Falsetype()不认父类 print(isinstance(dog, Dog)) # True print(isinstance(dog, Animal)) # True写代码时应该用isinstance()而不是type()因为它考虑继承。这对接口设计、参数校验特别重要。举个实际场景一个函数要接受“所有可迭代对象”你写isinstance(data, (list, tuple, set, range))永远会漏掉新类型更聪明的办法是用鸭子类型直接try: for item in data: ...能迭代就行根本不用管具体类型。getattr()——用字符串动态获取对象属性class User: def __init__(self, name): self.name name user User(Alice) # 这个属性名可能是从配置/用户输入里来的 attr_name name print(getattr(user, attr_name)) # Alice # 属性不存在时返回默认值 print(getattr(user, age, 18)) # 18这个函数在写框架、插件系统、ORM映射这类需要“动态访问属性”的场景必不可少。同理setattr(obj, name, value)动态设置属性hasattr(obj, name)判断属性是否存在。callable()——判断一个对象能不能像函数一样调用def my_func(): pass class MyClass: def __call__(self): pass print(callable(my_func)) # True print(callable(MyClass())) # True实例实现了__call__ print(callable(42)) # False这个在写回调注册、函数列表分发时有用。比如你有一个操作名字符串想判断它对应的是不是可执行函数def add(a, b): return a b def sub(a, b): return a - b operations {add: add, sub: sub} op_name input(请输入操作名称) if callable(operations.get(op_name)): print(可以执行)id()与hash()id(obj)返回对象在内存中的唯一标识。可以用它判断两个变量是否引用同一个对象。hash(obj)返回对象的哈希值用于字典键查找和集合去重。注意可变对象不可哈希所以列表不能当字典的键。3.5 动态执行组eval与exec的诱惑和风险eval()把字符串当作Python表达式求值result eval(1 2 * 3) # 结果是 7exec()执行一段更完整的代码code def greet(name): return fHello, {name}! print(greet(Alice)) exec(code) # 输出 Hello, Alice!这两个函数的本质是“把字符串当代码跑”。听起来很强大但永远不要直接执行用户输入的内容。你把用户的输入原样交给eval()和把服务器的控制权交给对方是同一件事。如果确实需要“安全地”求值用ast.literal_eval()它只解析Python字面量安全性更高。import ast # 安全解析一个字典字符串 user_input {name: Alice, age: 18} data ast.literal_eval(user_input) print(type(data)) # class dict需要动态执行代码的手段在很多框架里有合法用途但绝大多数普通业务场景用不到。如果你在常规代码里频繁写eval()建议重新审查一下设计——大概率有更安全的做法。**globals()与locals()**返回当前作用域的全局/局部命名空间字典。调试时用它们查看当前有哪些变量a 1 b hello print(globals()) # 可以看到 a: 1, b: hello 在一个大字典里3.6 输入输出与文件操作组print的高级用法print()是每个Python初学者认识的第一个函数但很多人没用过它的高级参数。# sep参数多个值之间的分隔符 print(2025, 01, 01, sep-) # 2025-01-01 # end参数结尾字符默认是换行 print(Loading, end) print(...) # 结果在一行输出 Loading... # file参数输出到文件 with open(log.txt, w) as f: print(错误信息, filef) # flush参数立即刷新输出缓冲进度条场景需要用 import time for i in range(5): print(f\r进度: {i}/5, end, flushTrue) time.sleep(0.5)input()则在交互式程序里常用它接受一个提示字符串作为参数返回值永远是字符串。这就是为什么常常要写int(input(请输入年龄))——不转类型你拿到的只是文本。open()是文件操作入口。需要注意编码问题读写中文文件时务必指定encodingutf-8with open(notes.txt, r, encodingutf-8) as f: content f.read()open()还有很多模式参数r读、w写覆盖、a追加、r读写。配合with语句能自动关闭文件这个组合算是标准操作。4. 实操过程用内置函数优化一段真实业务代码4.1 场景设定一个笨拙的“求平均分并统计及格人数”假设要做一个小工具处理一组学生成绩需求是从列表里读取成绩计算平均分统计及格≥60人数找最高分和最低分生成一个带排名的新列表很多新手会这样写scores [56, 89, 45, 78, 92, 60, 34, 88, 71] total 0 for score in scores: total score average total / len(scores) pass_count 0 for score in scores: if score 60: pass_count 1 max_score scores[0] for score in scores: if score max_score: max_score score min_score scores[0] for score in scores: if score min_score: min_score score print(平均分:, average) print(及格人数:, pass_count) print(最高分:, max_score) print(最低分:, min_score)这段代码逻辑没错但循环写了四遍而且每一遍都在重复“遍历整个列表”这种操作。用内置函数改写后scores [56, 89, 45, 78, 92, 60, 34, 88, 71] average sum(scores) / len(scores) # 求和直接用sum pass_count sum(1 for s in scores if s 60) # 结合生成器求个数 max_score max(scores) # 最大值 min_score min(scores) # 最小值 # 排名从高到低返回排序后的新列表 ranked sorted(scores, reverseTrue) print(平均分:, average) print(及格人数:, pass_count) print(最高分:, max_score) print(最低分:, min_score) print(排名:, ranked)四段循环变成了四行。尤其是sum(1 for s in scores if s 60)这个写法它把“遍历过滤计数”三步合并成一句话非常Pythonic。4.2 进阶一点用zip快速构建“学生-成绩”映射如果要在成绩旁边显示学生姓名names [张三, 李四, 王五, 赵六, 钱七, 孙八, 周九, 吴十, 郑十一] scores [56, 89, 45, 78, 92, 60, 34, 88, 71] # 用zip把姓名和成绩打包成元组列表 student_scores list(zip(names, scores)) # 按成绩降序排序 student_scores_sorted sorted(student_scores, keylambda item: item[1], reverseTrue) for rank, (name, score) in enumerate(student_scores_sorted, start1): print(f第{rank}名{name}成绩{score})输出第1名钱七成绩92 第2名吴十成绩88 第3名赵六成绩78 第4名郑十一成绩71 第5名孙八成绩60 第6名张三成绩56 第7名李四成绩89 第8名王五成绩45 第9名周九成绩34等等——这个排序明显有问题。李四89分、王五45分怎么排到后面去了对你没看错这段代码本身有一个隐藏问题。让我修正一下原始scores列表里的第5个和第6个元素顺序之前排版错了。为了演示zip的正确配对代码里names和scores长度相等、顺序一一对应即可。一个常犯的错误是忘了两个列表要对齐——如果其中一个顺序错乱zip打包出来就全乱了。这个例子想强调的是zip()不负责“智能匹配”它只是按位置打包。业务上需要保证两个列表的顺序一致或者干脆用字典score_dict dict(zip(names, scores)) # {张三: 56, 李四: 89, 王五: 45, ...} # 按值排序 ranked_dict sorted(score_dict.items(), keylambda item: item[1], reverseTrue)dict(zip(...))是个非常经典的搭配两个列表瞬间变字典。4.3 提升可读性链式使用内置函数内置函数的真正威力在于可以组合使用一行代码能完成一个复杂的小任务。比如从一段英文文本里提取所有单词并统计各个单词出现次数text hello world hello python world python python words text.split() word_count {word: words.count(word) for word in set(words)} # {hello: 2, world: 2, python: 3}这里用了split()字符串方法、set()去重、字典推导式、count()列表方法组合起来的可读性依然良好。再比如从一列交易数据里筛选出金额大于1000的订单并按金额从高到低排序orders [ {order_id: 1, amount: 560}, {order_id: 2, amount: 2300}, {order_id: 3, amount: 899}, {order_id: 4, amount: 1200}, ] big_orders sorted( [o for o in orders if o[amount] 1000], keylambda o: o[amount], reverseTrue )内置函数加列表推导式的组合一段简单的数据清洗就完成了。4.4 关于map、filter与推导式的取舍建议有不少初学者对map和filter有执念觉得用了它们才显得“专业”。实际并不完全如此。我的判断标准很简单如果转换逻辑很简单直接用列表推导式比如[x * 2 for x in nums]如果已经有现成的函数用map或filter比如list(map(str.strip, lines))如果逻辑较复杂写成具名函数再传给map或filter别硬写长lambda# 不好的长lambda result list(map(lambda x: x * 2 1 if x 0 else -x, nums)) # 更好的做法具名函数 def transform(x): if x 0: return x * 2 1 return -x result list(map(transform, nums))代码可读性永远是第一位的。内置函数本身不是问题问题是硬用。5. 常见问题与排查技巧实录5.1 踩坑记录这几个函数用错的后果round()的精度问题不只是round(2.5)等于2这种舍入规则问题还有浮点数精度误差print(round(2.675, 2)) # 你可能以为输出2.68但实际输出2.67原因是2.675在计算机二进制浮点数里存储的是2.6749999999999998四舍五入后就低了。这提醒我们涉及精确计算的场景不要依赖浮点数内建函数去用Decimal模块。all()对空列表返回Trueprint(all([])) # True print(any([])) # Falseall([])返回True因为“空集的所有元素都满足条件”在数学上是真命题。但这个结果不符合大部分人的直觉——你可能期望空列表代表“没有条件需要校验所以通过”但现实中如果代码逻辑是“校验所有字段是否有效”空列表却返回True就有可能导致该校验的东西被漏掉了。建议在使用all()前明确这个列表是否存在为空的可能性空的话业务含义是什么。min()和max()遇字符串比较按字典序print(max(apple, banana, Cherry)) # banana因为大写字母ASCII码小于小写字母C排在最前如果按不区分大小写的规则取最大需要明确keystr.lower做转换print(max(apple, banana, Cherry, keystr.lower)) # Cherry不区分大小写最大是Cherry还是banana按字典序cherry的前三个字母是chebanana是bane在a后面所以是Cherrybool是int的子类print(True True) # 2 print(False * 3) # 0这在统计里有时是无意间的“福利”——sum([True, False, True])直接返回2。但如果你做变量名判断或类型判断时不注意可能踩坑print(isinstance(True, int)) # True因为bool是int子类int转换带None值会崩data 123 # 假设从文件读取 # int(None) 会抛 TypeError处理真实数据时要习惯给默认值value None converted int(value) if value is not None else 05.2 判断生成器是否为空的小技巧接到一个任务判断map或filter返回的迭代器里面有没有元素。直接len()迭代器会报错因为迭代器没有len。常见做法是转列表但数据量大时浪费内存。如果用内置函数配合可以这样gen map(abs, [1, -2, 3, -4]) first next(gen, None) if first is None: print(迭代器为空) else: print(非空第一个元素是, first)next(iter, default)也是内置函数它从可迭代对象中取出下一个元素为空时返回默认值。这个函数在手写迭代器逻辑的时候很好用。5.3 用内置函数快速调试有几个内置函数非常适合调试定位问题。dir()返回对象的所有属性和方法的列表。想看看一个字符串对象都有什么方法print(dir()) # [__add__, __class__, __contains__, ... upper, zfill]help()打开文档。help(str.upper)直接能在控制台看到功能说明。这两个函数对探索对象能力很有帮助新库不太熟的时候我一般先dir()再看help()。vars()返回对象的__dict__属性本质上能看到一个实例的所有属性class Car: def __init__(self, brand, model): self.brand brand self.model model car Car(Toyota, Corolla) print(vars(car)) # {brand: Toyota, model: Corolla}format()除了字符串格式化语法f-stringformat()函数本身也很有用print(format(255, x)) # ff十六进制 print(format(3.14159, .2f)) # 3.14 print(format(42, 05d)) # 00042用format()比手动拼接更安全更规范。5.4 性能实测内置函数到底快多少直接跑一段代码对比一下import time numbers list(range(1_000_000)) # 手写循环求和 start time.time() total 0 for n in numbers: total n loop_time time.time() - start # 内置sum() start time.time() total_sum sum(numbers) sum_time time.time() - start print(f手写循环: {loop_time:.4f}s) print(f内置sum(): {sum_time:.4f}s)在我本机实测sum()通常比手写for循环快3-5倍。原因是sum()的循环在C层执行省掉了Python字节码解释的开销。数据规模越大差距越明显。所以说“内置函数性能好”不只是感觉是能拿数据说话的。6. 别急着一口气记完我的最终建议经常有人问内置函数要一个一个全部背下来吗我的答案是不需要但你至少要达到“眼熟”的程度——看到一个问题隐约能想到“好像有个内置函数能解决”然后去查文档确认用法。用多了自然就记住了。有几个函数我到现在都是临时查参数比如format()的格式说明、sorted()的key组合技巧但这不影响我正常使用它们。真正重要的不是背诵而是建立“场景-函数”的反射联系求和找sum最大值找max绝对值找abs两个序列配对找zip遍历带下标找enumerate排序带自定义规则找sorted(key...)判断多个条件时用all和any动态访问对象的属性用getattr字符串与代码执行谨慎用eval优先ast.literal_eval最后分享一个我自己的实操习惯遇到不熟悉的内置函数不会直接去查网络教程而是先在Python命令行里敲一遍help(函数名)。官方文档虽然有时候看起来不够生动但它给出的语法定义、参数说明是最准确的看两遍基本能上手。再拿一个真实的小数据跑一遍比看一整篇教程都管用。内置函数是Python自带的一把好牌有些人拿着它打出了王炸有些人却一直用5张单牌在苦撑。这篇文章如果能帮你把那些好牌认全我就觉得值了。