
前几篇聊了聊Python入门路线和环境搭建有朋友在后台问我入门阶段到底该学哪些Python模块才能少走弯路这个问题问得特别好。模块是Python最好的积木但市面上的推荐清单动不动就列出三四十个新手看着就头大。这篇作为适合新手小白学习的Python模块系列的第四篇我换个思路不打算铺开讲一堆模块冰山一角而是挑出4个我反复验证过、八成以上日常脚本都会用到的模块从选型思路讲到实操细节再带你把它们组合成一个小工具。学过之后你会发现不看框架也能写出很实用、很漂亮的小脚本。1. 为什么建议新手把学习重心放在标准库模块上先说段不太中听但真实的话很多新手学Python摔跟头不是不够努力而是顺序反了。我见过太多人Python刚会写for循环就急着装框架库跟着别人的项目抄。一抄抄出一个几十个依赖的工程最后连报错是第三方库版本不兼容还是自己代码写错都分不清。这种感觉就像还没学会走路就开始越野跑摔是必然的。回到模块本身。初学阶段你和Python的关系就是你和标准库模块的关系。Python官方打包发布的时候已经内置了一大批模块——处理文件用os处理JSON数据用json做日期换算用datetime写正则匹配用re做数学计算用math。它们不需要额外安装不需要pip下载不需要考虑版本冲突装好Python那一刻就全部躺在你的解释器里等着被你用。选择标准库模块作为学习核心有三个天然优势这是任何第三方库都给不了的。第一零安装阻力。初学者最怕的就是环境问题。你在官网下载Python安装包勾选好环境变量命令行输入python能进交互模式就能上手标准库模块。整个过程跟第三方库一点关系都没有自然少了一大半报错来源。第二报错定位容易。标准库的代码经过了PyPI上无数项目的检验坑早就被填平了。多数情况下你写的代码报错问题几乎肯定在你自己身上而不是模块本身有缺陷。这种错得明明白白的体验对新手建立排查信心特别重要。第三官方文档极其详实。Python官网的文档结构非常稳定每个模块底下都有常用用法完整函数列表示例代码。对新手来说这就是最好的教科书比任何二手的视频教程都值得反复翻。当然这并不意味着你永远不用第三方库。requests这种库几乎成了事实标准我们也得学。但主次关系要摆正标准库是你的主战场第三方库是你在标准库基础之上的扩展。地基不牢再好看的墙都是虚的。2. 筛选适合新手的Python模块我看这四个维度搜索框里输入Python模块推荐页面能翻十几屏。os、sys、json、re、random、datetime、collections、itertools、functools、logging……每个看起来都很厉害每个都有人推荐。新手最大的困境不是没得选而是选项太多不知道怎么挑。根据我这些年带新人和自己被坑出来的经验选模块之前先过四道筛子留下的基本都是值得学的。2.1 是否属于标准库能否开箱即用这个标准前面讲过但值得单独拎出来强调。学一个模块之前先问一句它是标准库吗如果答案是需要另外pip install那对新手来说已经多了一道门槛。不是说不可以学第三方库而是建议你把标准库的基础打得差不多了再去碰那些需要额外安装的东西。这样一旦出问题你能判断到底是代码问题还是环境问题。2.2 是否经常出现在日常脚本里有些模块很有趣但实用频率极低比如想学tkinter做桌面小软件、用sockets手写网络服务这些对新手来说都太远了。我更推荐优先学习那些高频场景绕不开的模块。什么是高频路径处理、数据序列化、网络请求、文本处理、日期计算这些几乎是每个脚本都会碰到的环节。高频模块你会反复使用用着用着自然就熟了根本不用刻意背API。2.3 学习反馈是否直观可见这条标准容易被忽视但对新手至关重要。学习需要正反馈最好能看得见摸得着。os模块运行完你能看到磁盘上真的多了一个新的文件夹json模块运行完能直观看到字符串和字典之间的相互转化requests模块运行完能真实地抓到网页内容。这种快速的、可见的正反馈比闷头看文档强太多。它让你觉得我跟电脑之间发生了真实交流而不是在背一堆用不上的定义。2.4 文档和社区资料是否成熟可查去翻一眼官方文档如果这个模块的函数有清晰的参数说明、有返回值解释、有代码示例旁边还有大量的中文教程和问答帖那它就是成熟的、适合新手的。如果一个模块文档残缺、论坛提问都没人回说明它太冷门或者太新了别碰。判断资料多不多的办法很简单去搜一下模块名 教程看看前排结果质量。教程数量多且内容靠谱的才值得投入时间。根据这套标准我筛出来的4个模块是os、json、requests、collections。下面详细拆解。3. 我反复验证过的4个模块分别解决什么问题这4个模块不是随便挑的它们覆盖了文件系统、数据交换、网络请求、数据结构这四个写脚本绕不开的领域。逐个来看它们到底解决了什么痛点。3.1 os文件系统和路径操作的总入口os是Python标准库里当之无愧的老大哥。你在资源管理器里能手动做的事用代码基本都能通过它完成获取当前工作目录、列出目录内容、创建文件夹、重命名、移动、删除文件、判断路径类型。不管是Windows还是macOS还是Linuxos模块提供的函数接口都是统一的它帮你屏蔽掉了操作系统的差异性。很多新手问os模块学了有什么用我举一个最实在的例子。假设你要整理一个塞满照片的文件夹把2023年拍的照片移动到2023目录2024年的移到2024目录。没有代码你只能手动挨个处理几百张文件有了os模块几行循环就自动化了。所有自动化脚本第一步几乎都是扫描目录操作路径这就是os的主场。顺带提醒os模块里还有两个重要成员os.path负责所有路径操作拼接、拆分、判断另外一个叫os.environ用来读写环境变量。初学者先把os.path用熟练后面很多高级脚本都离不开它。3.2 json跨系统数据交换的通用语言现在的互联网世界里JSON的地位等同于当年XML的地位甚至更高。前后端通信返回的是JSON配置文件用的是JSON很多数据库工具导出数据用的也是JSON。Python的json模块就是你和这股通用数据洪流对接的桥梁。它做的事情极度聚焦就两个方向把Python对象字典、列表等转成JSON字符串这叫序列化把JSON字符串还原成Python对象这叫反序列化。新手经常不理解为什么存数据非要转成字符串直接用字典存在文件里不行吗答案是字典只是Python内部的数据结构只有Python自己看得懂JSON是纯文本任何语言、任何系统、任何网络工具都能解析。你的程序要跟别人写的服务通信就必须使用这种世界语。3.3 requests网络请求事实上的标配严格来说requests是第三方库不是标准库。我依然把它列为新手必修模块原因很简单只需要一行代码你能发起一个HTTP请求并拿到响应这个简单到极致的体验太适合新手建立自信了。官方自带的urllib能做到同样的事情但是用起来又繁琐又绕。urllib的请求对象、响应对象、异常处理都没有requests那么人性化新手很容易被它的复杂API劝退。requests帮你把HTTP协议下面那一堆细节包得严严实实URL拼接、请求头、响应头、Cookie管理、超时处理、重定向……你只要记住get是拿数据、post是交数据就能处理绝大多数网络请求场景。学会了它以后碰到httpx、aiohttp这些更高级的库你会发现思路是共通的学起来飞快。3.4 collections让常见数据结构用起来更顺手collections是标准库里的宝藏模块也是新手最容易被忽视的。它并不引入全新的数据结构而是在Python内置的字典、列表、元组之上做增强让一些本来写起来很别扭的操作变得非常干净。举个例子统计一段文本里每个单词出现的次数。如果用内置字典你得先判断这个键在不在不在要先初始化为0。如果用collections里的defaultdict键不存在时会自动用默认值初始化代码直接就能写count[word] 1。同样的逻辑普通字典要写三行defaultdict只写一行这就是collections的价值让你付出极小的学习成本换来代码质感的巨大提升。4. 高频用法代码演示把关键参数讲明白选好了模块下面进入实操。我不会把所有函数都列出来——那只会让新手更迷茫。只讲每个模块最常用的典型操作每一个都配上场景和代码你照着敲一遍就能在本地跑通。4.1 os模块路径拼接、目录遍历、文件判断一招掌握动手之前先确认Python环境是好的。打开命令行输入python --version能输出版本号就说明环境没问题。如果提示找不到命令多半是安装时没有勾选Add Python to PATH需要去系统环境变量里手动配置。这一步搞不定的话后面所有模块都用不利索。来看os模块的基本操作import os # 1. 获取当前工作目录 current_dir os.getcwd() print(当前目录, current_dir) # 2. 列出目录下的所有文件和文件夹 items os.listdir(current_dir) print(目录内容, items) # 3. 创建目录 os.mkdir(test_folder) # 只能创建单层目录 os.makedirs(a/b/c, exist_okTrue) # 创建多层目录exist_ok避免重复报错 # 4. 路径拼接 full_path os.path.join(current_dir, test_folder, demo.txt) print(拼接后的完整路径, full_path) # 5. 路径判断 print(路径是否存在, os.path.exists(full_path)) print(是否是文件, os.path.isfile(full_path)) print(是否是目录, os.path.isdir(current_dir)) # 6. 重命名 os.rename(old.txt, new.txt) # 7. 删除 os.remove(temp.txt) # 删除文件 os.rmdir(empty_folder) # 删除空目录这段代码有四个细节新手必须弄明白否则后面写自动化脚本一定会踩坑。第一个路径拼接永远用os.path.join不要手动拼字符串。Windows路径分隔符是反斜杠\macOS和Linux是正斜杠/。你要是图方便写成f{dir}/{filename}换台电脑跑八成就不对了。os.path.join会智能判断当前操作系统的分隔符让代码在不同平台之间无缝移植。这是专业写法和业余写法的分水岭。第二个makedirs的exist_okTrue参数是必加的。如果不加目标目录已经存在时会抛FileExistsError。加上之后目录存在就安安静静跳过不存在才新建。你写脚本时不知道前一次运行有没有创建过这个目录exist_okTrue帮你省掉一大堆手动判断。第三个区分os.path.exists、os.path.isfile、os.path.isdir。exists只判断路径在不在isfile判断路径是不是一个普通文件isdir判断路径是不是一个目录。三者的使用场景完全不同新手最喜欢混着用建议多敲几次体会差别。第四个Python官方现在推荐使用pathlib处理路径它的Path对象比os.path更直观。但os模块在系统编程、老代码兼容性上的地位无法撼动何况很多第三方库内部大量依赖os你学会它绝不亏。两者不冲突可以并行熟悉先把os练好已经能解决绝大多数问题了。4.2 json模块序列化与反序列化的标准动作两个参数定生死JSON的场景一句话概括你的程序只要跟外部系统交换数据十有八九要用它。把json模块的高频操作过一遍import json # Python对象 - JSON字符串序列化 data {name: 小明, age: 18, hobbies: [篮球, 编程]} json_str json.dumps(data, ensure_asciiFalse, indent2) print(json_str) # JSON字符串 - Python对象反序列化 json_input {name: 小明, age: 18} parsed json.loads(json_input) print(parsed[name]) # 写入JSON文件 with open(data.json, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) # 读取JSON文件 with open(data.json, r, encodingutf-8) as f: loaded json.load(f) print(loaded[hobbies])新手看到的第一句话可能开始背名字dumps和loads是字符串之间的转换dump和load是文件之间的转换。这个区分要记牢而且我教你一个记忆技巧带s的都和String字符串有关。真正值得重点讲的是两个参数它们能决定你打开文件时看到的到底是人话还是乱码。先是ensure_asciiFalse。json.dumps默认会把所有非ASCII字符比如中文转成\uXXXX形式的转义序列。小明会变成\u5c0f\u660e。这在程序解析层面完全合法可你要是用文本编辑器打开保存好的JSON文件满屏转义符你根本没法阅读。加上ensure_asciiFalse之后中文就以原样写入文件。凡是你的数据里有中文这个参数必须写没有例外。再是indent2。不给它json.dumps输出的就是一行超级长的字符串结构完全看不清。给上indent2每个层级缩进两个空格整个JSON的结构一目了然。调试接口数据、检查配置文件时这个参数是你的眼睛。文件读写时还有第三个容易忽略的点open()里的encodingutf-8。在Windows上Python默认的文本编码是gbk准确说是locale.getpreferredencoding()的结果。你打开一个UTF-8编码的JSON文件如果不指定encodingutf-8轻则中文乱码重则直接给你一个UnicodeDecodeError。所以养成习惯每次open文件都显式声明编码。同样地写文件的时候也必须指定w模式加encodingutf-8两个地方都不能漏。最后说下with open这个写法不是可选项是建议项。with块管理着文件的生命周期块内代码执行完文件会被自动关闭哪怕中间抛了异常也能保证关闭。如果你用open()打开文件后忘记close()在某些情况下文件会被占用导致其他程序无法读写。这也是新手最容易犯的低级错误文件操作一律用with养成习惯就不会出问题。4.3 requests模块从GET到POST把网络请求串成一条线request是请求库里的明星也是很多爬虫项目的起点。首次使用先安装确认一下pip install requests如果提示pip不是内部或外部命令试试这个替代写法python -m pip install requests这个写法不依赖pip是否在环境变量里而是让Python解释器自己去调用pip模块兼容性更好。Windows用户如果两个命令都不行大概率是Python的Scripts目录没加进PATH回去检查环境变量。安装好之后看常规用法import requests # 1. GET请求 resp requests.get(https://httpbin.org/get) print(状态码, resp.status_code) print(响应前200字符, resp.text[:200]) # 2. 带参数的GET请求 params {keyword: python 模块, page: 1} resp requests.get(https://httpbin.org/get, paramsparams) print(实际请求URL, resp.url) # 3. POST请求提交JSON数据 payload {username: demo, password: 123456} resp requests.post(https://httpbin.org/post, jsonpayload) print(服务器返回, resp.json()) # 4. 设置超时 resp requests.get(https://httpbin.org/delay/2, timeout5) print(内容, resp.text)requests的API设计特别符合直觉你只需要记住四个核心对象requests.get、requests.post、resp.text、resp.json()。想要什么就调什么它不会逼你理解底层HTTP协议。但正因为这么傻瓜化新手很容易掉进一个陷阱不写timeout参数。我见过太多爬虫新手写一个requests.get(url)就完事了结果目标网站响应很慢或者配置了延迟程序就一直傻等在那里几十分钟不结束。这不是你的代码卡住了而是它真的在等一个永远等不到的响应。解决办法很简单每次请求都加timeout参数比如timeout5超过5秒没有响应就抛Timeout异常由你来决定如何处理。我甚至建议初学者把timeout当作必填参数来写养成这个习惯能救你无数回。再讲一个高频困惑resp.text和resp.content的区别。resp.text是文本形式的响应内容适合HTML、JSON这种可打印字符resp.content是bytes字节形式适合下载图片、文件这类二进制数据。如果你用resp.text去处理一张图片你得到的将是一堆乱码反过来用resp.content去读文本还得手动decode成字符串。两者适用场景不同选择时先思考内容类型。另外这个jsonpayload参数也很值得注意。requests会帮你在内部把payload字典序列化成JSON字符串并且自动设置Content-Type头为application/json。这是POST提交JSON数据最标准、最省事的写法比你去手动json.dumps再传data参数要可靠得多。4.4 collections模块三个容器解决三类别扭collections不改变你已有的数据结构知识它只是在原有基础上提供增强。我用三个场景把它最常见的用法一次讲清。from collections import defaultdict, Counter, namedtuple # 场景1defaultdict省去键缺失判断 words [apple, banana, apple, orange, banana, apple] count defaultdict(int) for w in words: count[w] 1 # 键不存在时自动创建并初始化为0 print(dict(count)) # 输出{apple: 3, banana: 2, orange: 1} # 场景2Counter一行完成词频统计 freq Counter(words) print(freq.most_common(2)) # 输出[(apple, 3), (banana, 2)] # 场景3namedtuple让元组字段有名字 Point namedtuple(Point, [x, y]) p Point(10, 20) print(p.x, p.y) # 输出10 20 print(p[0], p[1]) # 输出10 20defaultdict可以理解为带默认值的字典。普通字典访问不存在的键会抛KeyError所以写统计逻辑时要先判断键在不在写出来就是这个样子if key in d: d[key] 1 else: d[key] 1而defaultdict(int)在遇到新键时会自动调用int()把默认值设为0于是d[key] 1永远不会因为键不存在而报错。它背后的思想是把容错逻辑交给数据结构去处理你的代码只负责表达业务逻辑。Counter是专门做计数的字典子类用途极其聚焦。你想要统计元素出现次数加找到出现最多的前几个它一行搞定。最典型的方法就是most_common()直接拿频率排行不用手动排序。namedtuple给元组里的位置元素起了名字。你用普通元组表示坐标只能point[0]、point[1]写多了根本分不清哪个是x哪个是y。namedtuple能让你用p.x、p.y访问同时又保留了元组不可变的性质。它特别适合定义那种字段固定、不需要修改的数据类型比如坐标、配置记录、用户信息等。虽然现代Python还有dataclass可以做更复杂的版本但namedtuple的轻量特性让它永远有它的位置。5. 新手用模块时最常踩的坑内含排查建议这个部分的价值我觉得不比前面所有代码低。以下五个坑是我在带新人和自己写代码的过程中反复遇到的每个都给出了直接可行的排查思路。5.1 导入模块时报ModuleNotFoundError它是新手遇到的第一座大山报错信息永远是No module named xxx。很多人看到第一反应是电脑坏了其实九成九是下面三种情况之一模块名拼写错误、模块没有安装、安装到了另一个Python环境。排查思路按顺序来。先在代码里确认模块名和官方文档完全一致大小写也要敏感。然后用pip show xxx确认模块是否已经安装。如果已经装了还是报错问题大概率出在环境变量。命令行里的python和你安装模块用的python可能不是同一个——特别常见的是电脑里装了多个Python版本pip装上去了Python 3.11而命令行默认跑的是Python 3.8。验证方法是在命令行执行python -c import sys; print(sys.executable)看它输出哪个路径再执行pip show看看模块装到哪个路径两个对上就好了。嫌麻烦的话干脆用它替代直接执行python -m pip install xxx保证装进当前python所在的环境。5.2 os.path.join拼接出来的路径不合预期很多新手理解错了join的行为。它不是简单地把两个字符串用斜杠粘起来而是一个有优先级判断的函数。如果传入的某个参数是绝对路径join会丢弃之前的所有内容从这个绝对路径开始重新拼。比如print(os.path.join(/a/b, /c/d.txt)) # 输出/c/d.txt而不是/a/b/c/d.txt这个特性经常让人摸不着头脑。排查方法很简单print出拼接结果看一眼然后想想是不是某个参数前多写了斜杠。这就是我前面强调的不要手动拼路径的另一个理由——join的行为比肉眼看起来要聪明得多学会它才能真正掌控路径生成。5.3 文件里的中文变成\uXXXX或乱码最典型的组合是json.dump写完文件打开一看全是一堆反斜杠u数字或者json.load读文件直接抛UnicodeDecodeError。前者是没加ensure_asciiFalse后者是没加encodingutf-8。排查思路非常简单粗暴写JSON文件和读JSON文件的代码里这两个参数一个都不能少。顺手再检查一下open()是不是用文本模式打开的json模块处理的就是文本文件不要用rb模式去读JSON然后自己再做decode那属于不必要的绕路。5.4 网络请求一直不返回像是被挂起题目多半出在timeout没设置。有些网站会对慢速请求做延迟响应或者在网络差的环境下很久才返回。如果没有timeout你的程序就会一直挂着。最快的排查方法就是把requests.get或者requests.post统一加上timeout参数比如timeout5然后捕获Timeout异常写个兜底逻辑打印提示。这是治本的方案。另外一个容易忽视的点是响应体过于庞大。有些服务器的接口会返回几百MB的数据默认requests会把它整个下载完自然显得卡。如果只需要部分内容考虑用streamTrue配合iter_content做流式读取。新手阶段可以先不深入流式但你要知道有流式响应这个方向等真正遇到大文件下载时再去搜索研究也不晚。5.5 遍历字典时修改字典引发RuntimeError新手很容易写出这种代码count {apple: 3, banana: 2, orange: 0} for k in count: if count[k] 0: del count[k]跑起来会报RuntimeError: dictionary changed size during iteration。原因是Python的字典迭代器是在遍历过程中动态扫描键的你一边遍历一边删键迭代器的位置就全错乱了。解决思路是先收集后删除to_delete [k for k, v in count.items() if v 0] for k in to_delete: del count[k]先把需要删除的键收集到一个列表里循环结束后再统一删除。这个不要在迭代中修改容器结构的原则同样适用于列表、集合。记住它可以省掉很多莫名其妙的内存和逻辑错误。6. 实战组合用这4个模块写一个自动整理下载文件夹的小工具模块学了不组合等于白学。最后我带你写一个能实际用起来的小脚本自动扫描下载文件夹把文件按扩展名分类移动到images、documents、archives等子目录同时生成一份JSON格式的整理记录。这个工具不难但几乎把前文讲到的东西全部串起来了。import os import json import time import shutil from collections import defaultdict # 定义分类规则 CATEGORY_RULES { images: [.jpg, .jpeg, .png, .gif, .bmp], documents: [.pdf, .docx, .doc, .txt, .md], archives: [.zip, .rar, .7z, .tar, .gz], code: [.py, .js, .java, .c, .cpp, .html, .css], videos: [.mp4, .avi, .mkv, .mov], music: [.mp3, .wav, .flac, .aac], } def classify_file(filename): 根据扩展名返回分类名 ext os.path.splitext(filename)[1].lower() for category, extensions in CATEGORY_RULES.items(): if ext in extensions: return category return others def organize_directory(target_dir, dry_runTrue): 扫描目录并把文件按分类移动到子目录 if not os.path.exists(target_dir): print(f目录不存在{target_dir}) return stats defaultdict(int) moved_files [] for filename in os.listdir(target_dir): full_path os.path.join(target_dir, filename) # 跳过文件夹本身 if os.path.isdir(full_path): continue category classify_file(filename) dest_dir os.path.join(target_dir, category) os.makedirs(dest_dir, exist_okTrue) dest_path os.path.join(dest_dir, filename) # 重名文件加时间戳避免覆盖 if os.path.exists(dest_path): name, ext os.path.splitext(filename) dest_path os.path.join(dest_dir, f{name}_{int(time.time())}{ext}) if dry_run: print(f[模拟] {full_path} - {dest_path}) else: shutil.move(full_path, dest_path) stats[category] 1 moved_files.append(dest_path) result { moved_count: len(moved_files), category_stats: dict(stats), target_dir: target_dir, } print(json.dumps(result, ensure_asciiFalse, indent2)) with open(os.path.join(target_dir, organize_record.json), w, encodingutf-8) as f: json.dump(result, f, ensure_asciiFalse, indent2) if __name__ __main__: organize_directory(rC:\Users\你的用户名\Downloads, dry_runTrue)使用流程是三步先在代码里把目标目录改成你自己的下载文件夹第一步运行dry_runTrue此时程序只会打印每一个文件的移动计划不会真正动你的文件你要做的是仔细核对分类结果是否合理。确认无误后把dry_run改为False再跑一遍这次才是真正移动文件同时生成一份organize_record.json记录。这个脚本为什么值得新手一行行拆开看因为它把前面讲的模块全部打通了。os.listdir负责遍历目录os.path.join负责拼路径os.path.splitext负责分离文件名和扩展名os.path.isdir负责跳过目录os.makedirs负责创建分类文件夹collections.defaultdict负责统计每种类型的文件数量json.dump负责把整理记录落盘shutil.move负责跨目录移动文件。每一行代码背后都有明确的功能读着读着你就会意识到模块的价值不是单个功能有多强大而是组合起来能解决真实问题。加上一个保护模式的设计也值得解释。dry_run参数的存在是为了让你对文件操作保留敬畏。移动文件是不可逆动作万一分类规则写错文件被移到奇怪的地方手忙脚乱找回来的体验很糟。先模拟再实操这个思路可以用在所有自动化脚本中。以后写任何批量改文件的脚本建议都加一个dry_run的开关这是对数据的尊重。对扩展方向你可以给它加上按修改月份归档、定时运行、把整理结果发送到接口等功能越改越好玩。等你把这些模块彻底掌握了也就具备了自己去折腾更复杂项目的能力了。7. 最后分享两个我在实际使用中沉淀下来的小经验在结束之前再分享两个不是代码、但对新手特别重要的经验。第一个是别背API。我写Python这么多年os里几十个函数至今不敢说全背下来正常开发中随时要翻文档。真正重要的能力不是记住某个模块有哪些函数而是当遇到文件路径处理、跨系统数据交换、发网络请求这类场景时脑海里立刻蹦出对应的模块名。这个场景-模块的对应直觉比背任何API都更重要。你练熟了自然会发现写代码时你查文档的次数越来越少因为你知道该去哪里找答案了。第二个是抄代码也要过脑子。搬运一段代码很容易但粘贴之前给自己三分钟问两个问题这段代码里每个import进来的模块分别负责干什么如果我删掉其中一行程序会发生什么变化带着这两个问题去抄代码哪怕一天只消化一小段坚持一个月你对模块的理解也会明显超过那些只按CtrlC快捷键的人。模块是Python给新手最好的礼物。它不要求你先懂计算机原理不需要你配置复杂的依赖只要你愿意打开命令行敲几行代码看到反馈然后一点点把散落的积木拼成自己的作品。这就是我理解的Python入门之路。下次再遇到问题找不到对应模块时不妨先把os、json、requests、collections这四块试一遍你会发现它们的覆盖面远超你的想象。