Python 常用第三方模块:站在巨人的肩膀上
引言:从"自带电池"到"应用商店"
上一篇我们讲了 Python 的内建模块——就像手机出厂预装的计算器、日历,开箱即用。
但真正的威力在于第三方模块——全球的 Python 开发者编写了超过 40 万个第三方包,发布在 PyPI(Python Package Index)上。这就像手机的应用商店:想修图?有 Pillow;想发网络请求?有 requests;想识别文件编码?有 chardet;想监控系统资源?有 psutil。
安装第三方模块只需要一行命令:
pip install 模块名生活化理解:内建模块是毛坯房自带的硬装(水电、地板),第三方模块是你自己买的家电(冰箱、洗衣机、空调)——按需安装,即装即用。
这一篇,我们深入讲解 4 个最经典、使用最广泛的第三方模块:Pillow(图像处理)、requests(网络请求)、chardet(编码检测)、psutil(系统监控)。每个模块都会讲透核心功能、实战案例和常见误区。
准备工作:pip 使用须知
在开始之前,先确保你会正确安装第三方模块:
# 安装单个模块
pip install Pillow
pip install requests
pip install chardet
pip install psutil
# 一次装多个
pip install Pillow requests chardet psutil
# 指定版本
pip install requests==2.31.0
# 升级
pip install --upgrade requests
# 卸载
pip uninstall requests
# 查看已安装的模块
pip list
# 查看某个模块的详细信息
pip show requests重要提醒:请务必在虚拟环境(venv)中安装,别污染全局环境!
国内加速:如果下载慢,可以使用国内镜像源:
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple一、Pillow:Python 的"图像处理车间"
1.1 模块简介
Pillow 是大名鼎鼎的 PIL(Python Imaging Library)的分支和继承者。PIL 早已停止更新(停留在 Python 2.x),Pillow 接手并持续维护至今,是 Python 图像处理的事实标准。
生活化理解:Pillow 就是一个数字暗房 + 修图工作室——裁剪、缩放、旋转、加水印、调滤镜、转格式,样样都行。
pip install Pillow注意:安装名是 Pillow(大写),导入名是 PIL(历史遗留):
from PIL import Image # ✅ 正确
import Pillow # ❌ 错误1.2 打开、查看、保存图片
from PIL import Image
# 打开图片
im = Image.open('photo.jpg')
# 查看基本信息
print(im.format) # 'JPEG' — 图片格式
print(im.size) # (1920, 1080) — 宽×高(像素)
print(im.mode) # 'RGB' — 色彩模式
# 保存为另一种格式(格式转换)
im.save('photo.png') # 根据扩展名自动选择格式常见色彩模式:
| 模式 | 含义 | 每像素通道 |
|---|---|---|
RGB | 红绿蓝三原色 | 3 |
RGBA | RGB + 透明度 | 4 |
L | 灰度图(黑白) | 1 |
1 | 二值图(纯黑白) | 1 位 |
1.3 缩放与裁剪
from PIL import Image
im = Image.open('photo.jpg')
# 缩放到指定尺寸
im_resized = im.resize((400, 300))
im_resized.save('photo_small.jpg')
# 等比缩放:制作缩略图(不会变形)
im.thumbnail((200, 200)) # 最长边不超过200
im.save('photo_thumb.jpg')
# 裁剪:crop((左, 上, 右, 下))
im_crop = im.crop((100, 100, 500, 400))
im_crop.save('photo_crop.jpg')resize vs thumbnail 的区别:
resize((400, 300)):强制缩放到 400×300,可能变形;thumbnail((200, 200)):等比缩放,最长边不超过 200,不会变形,且直接修改原对象。
1.4 旋转与翻转
# 旋转 45 度(逆时针)
im.rotate(45).save('rotated.jpg')
# 旋转并填充空白区域为白色
im.rotate(45, expand=True, fillcolor='white').save('rotated_full.jpg')
# 左右镜像翻转
im.transpose(Image.FLIP_LEFT_RIGHT).save('flip.jpg')
# 上下翻转
im.transpose(Image.FLIP_TOP_BOTTOM).save('flop.jpg')rotate 的 expand 参数:图片旋转 45 度后,四个角会超出原来的矩形范围。expand=False(默认)会裁掉超出部分;expand=True 会扩大画布容纳完整图片。
1.5 滤镜与图像增强
from PIL import Image, ImageFilter, ImageEnhance
im = Image.open('photo.jpg')
# 模糊效果(常用于隐私打码)
im.filter(ImageFilter.GaussianBlur(radius=10)).save('blur.jpg')
# 轮廓效果
im.filter(ImageFilter.CONTOUR).save('contour.jpg')
# 锐化
im.filter(ImageFilter.SHARPEN).save('sharp.jpg')
# 调整亮度(1.0=原始,>1变亮,<1变暗)
bright = ImageEnhance.Brightness(im).enhance(1.5)
bright.save('brighter.jpg')
# 调整对比度
contrast = ImageEnhance.Contrast(im).enhance(1.3)
contrast.save('contrast.jpg')
# 调整色彩饱和度(0=黑白)
color = ImageEnhance.Color(im).enhance(0.0)
color.save('gray.jpg')1.6 加水印
from PIL import Image, ImageDraw, ImageFont
im = Image.open('photo.jpg')
# 创建画笔
draw = ImageDraw.Draw(im)
# 加载字体(Windows 自带微软雅黑)
font = ImageFont.truetype('msyh.ttc', 36)
# 在右下角绘制文字水印
text = '@我的版权'
w, h = im.size
draw.text((w - 300, h - 60), text, font=font, fill=(255, 255, 255, 128))
im.save('watermarked.jpg')1.7 图片拼接
from PIL import Image
im1 = Image.open('a.jpg')
im2 = Image.open('b.jpg')
# 创建一张新画布(宽度=两图之和)
new_im = Image.new('RGB', (im1.width + im2.width, im1.height))
new_im.paste(im1, (0, 0)) # 左图贴在 (0,0)
new_im.paste(im2, (im1.width, 0)) # 右图贴在左图右边
new_im.save('merged.jpg')1.8 实战案例:批量生成缩略图
from PIL import Image
from pathlib import Path
def make_thumbnails(src_dir, dst_dir, size=(300, 300)):
"""批量把 src_dir 下的图片生成缩略图到 dst_dir"""
Path(dst_dir).mkdir(exist_ok=True)
for file in Path(src_dir).glob('*.jpg'):
im = Image.open(file)
im.thumbnail(size)
out_path = Path(dst_dir) / file.name
im.save(out_path)
print(f'处理完成: {file.name}')
make_thumbnails('photos', 'thumbnails')1.9 常见误区
误区 1:Image.open() 后忘记关闭文件。
真相:大文件处理时最好用 with 或显式 close():
with Image.open('big.jpg') as im:
im.thumbnail((300, 300))
im.save('thumb.jpg')误区 2:处理 JPG 时透明度丢了。
真相:JPG 不支持透明通道。如果图片是 RGBA 模式,保存为 JPG 前要先转换:
im = Image.open('icon.png') # RGBA
im.convert('RGB').save('icon.jpg') # 先转成 RGB误区 3:resize 和 thumbnail 混用出错。
真相:resize 返回新对象,thumbnail 原地修改不返回值:
im2 = im.resize((400, 300)) # im 不变,im2 是新图
im.thumbnail((200, 200)) # im 被直接修改,返回 None
im3 = im.thumbnail((100, 100)) # ❌ im3 是 None!二、requests:最好用的"网络快递员"
2.1 模块简介
Python 自带的 urllib 能发 HTTP 请求,但接口啰嗦。requests 的口号是 "HTTP for Humans"(为人类设计的 HTTP 库),接口优雅到令人惊叹,是 Python 生态中下载量最高的库之一。
pip install requestsurllib vs requests 对比:
# urllib 发 POST 请求
from urllib.request import urlopen, Request
from urllib.parse import urlencode
data = urlencode({'key': 'value'}).encode('utf-8')
req = Request('https://httpbin.org/post', data=data, method='POST')
with urlopen(req) as resp:
result = resp.read().decode('utf-8')
# requests 发同样的请求
import requests
r = requests.post('https://httpbin.org/post', data={'key': 'value'})
result = r.text2.2 GET 请求
import requests
# 最简单的 GET
r = requests.get('https://httpbin.org/get')
# 查看响应
print(r.status_code) # 200 — HTTP 状态码
print(r.text) # 响应内容(字符串)
print(r.headers) # 响应头(类字典对象)
print(r.encoding) # 'utf-8' — 编码
# 带查询参数(自动拼接到 URL)
r = requests.get('https://httpbin.org/get', params={'name': '张三', 'page': 2})
print(r.url) # https://httpbin.org/get?name=%E5%BC%A0%E4%B8%89&page=2
# 带请求头
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
r = requests.get('https://httpbin.org/get', headers=headers)
# 设置超时(重要!防止程序卡死)
r = requests.get('https://httpbin.org/get', timeout=5) # 5秒超时2.3 POST 请求
import requests
# 表单提交(application/x-www-form-urlencoded)
r = requests.post('https://httpbin.org/post', data={'username': 'admin'})
# JSON 提交(application/json)— 现代 API 的主流
r = requests.post('https://httpbin.org/post', json={'username': 'admin', 'age': 18})
# 上传文件(multipart/form-data)
files = {'file': open('report.xlsx', 'rb')}
r = requests.post('https://httpbin.org/post', files=files)data= vs json= 的区别:
| 参数 | Content-Type | 适用场景 |
|---|---|---|
data={'k': 'v'} | application/x-www-form-urlencoded | 传统网页表单 |
json={'k': 'v'} | application/json | 现代 RESTful API |
2.4 处理 JSON 响应
现代 API 几乎都返回 JSON,requests 内置了解析方法:
import requests
r = requests.get('https://httpbin.org/json')
data = r.json() # 自动解析为 Python 字典
print(data['slideshow']['author'])常见误区:r.json() 在响应不是 JSON 时会抛异常。稳妥写法:
r = requests.get(url)
if r.status_code == 200:
try:
data = r.json()
except ValueError:
print('响应不是有效的 JSON:', r.text[:200])2.5 Session:保持登录状态
有些网站登录后才能访问内部页面。登录本质上是一次 POST,成功后服务器通过 Cookie 记住你。Session 对象会自动保存和携带 Cookie:
生活化理解:普通请求像每次进小区都重新登记;Session 像办了门禁卡,刷卡即入。
import requests
# 创建会话
s = requests.Session()
# 第一步:登录(服务器返回的 Cookie 自动存入 session)
s.post('https://example.com/login', data={'user': 'admin', 'pwd': '123456'})
# 第二步:访问需要登录的页面(自动携带 Cookie)
r = s.get('https://example.com/dashboard')
print(r.text)
# Session 还能统一设置请求头
s.headers.update({'User-Agent': 'MyApp/1.0'})2.6 下载文件
import requests
# 小文件:一次性读入内存
r = requests.get('https://example.com/logo.png')
with open('logo.png', 'wb') as f:
f.write(r.content) # content 是字节,text 是字符串
# 大文件:流式下载(防止撑爆内存)
with requests.get('https://example.com/big.zip', stream=True) as r:
r.raise_for_status() # 状态码不是 2xx 就抛异常
with open('big.zip', 'wb') as f:
for chunk in r.iter_content(chunk_size=8192): # 每次 8KB
f.write(chunk)r.text vs r.content:
| 属性 | 类型 | 适用 |
|---|---|---|
r.text | str(已解码) | 网页 HTML、JSON、文本 |
r.content | bytes(原始字节) | 图片、压缩包等二进制文件 |
2.7 异常处理
网络请求充满不确定性——超时、断网、DNS 失败、服务器 500……必须做异常处理:
import requests
try:
r = requests.get('https://example.com/api', timeout=5)
r.raise_for_status() # 4xx/5xx 状态码会抛 HTTPError
data = r.json()
except requests.exceptions.Timeout:
print('请求超时')
except requests.exceptions.ConnectionError:
print('网络连接失败')
except requests.exceptions.HTTPError as e:
print(f'HTTP 错误: {e}')
except requests.exceptions.RequestException as e:
# 上面所有异常的父类,兜底用
print(f'请求失败: {e}')2.8 常见误区
误区 1:不设置 timeout。
真相:默认永不超时!服务器不响应时程序会永远卡死。生产代码必须设置 timeout。
误区 2:循环里反复 requests.get()。
真相:每次都建立新 TCP 连接,开销大。循环请求同一个网站应该用 Session(自动连接复用)。
误区 3:用 if r.status_code == 200 判断成功。
真相:2xx 都表示成功(200 OK、201 Created、204 No Content)。更规范的写法:
if r.ok: # 状态码 < 400 即为 True
...
# 或
r.raise_for_status() # 失败直接抛异常三、chardet:文件编码的"侦探"
3.1 模块简介
你是否遇到过打开一个文本文件,满屏都是"锟斤拷""烫烫烫"式的乱码?这是因为用错了编码。
全世界的文本编码五花八门:UTF-8、GBK、GB2312、Big5、Shift_JIS……拿到一个来路不明的文件,怎么知道它是什么编码?
chardet(character detect,字符检测)就是干这个的——它会分析文件的字节特征,猜出最可能的编码。
pip install chardet生活化理解:chardet 像一位语言学家,拿到一段陌生文字,看看笔画特征就能判断:"这 80% 是日文,15% 可能是中文繁体"。
3.2 基本用法
import chardet
# 检测字节串的编码
data = b'\xc4\xe3\xba\xc3' # GBK 编码的"你好"
result = chardet.detect(data)
print(result)
# {'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}
# 用检测到的编码解码
text = data.decode(result['encoding'])
print(text) # 你好返回结果的含义:
| 字段 | 含义 |
|---|---|
encoding | 猜测的编码名称(猜不出来是 None) |
confidence | 置信度(0~1,越接近 1 越确定) |
language | 猜测的语言 |
3.3 实战:读取未知编码的文件
import chardet
def read_any_file(path):
"""读取任意编码的文本文件"""
with open(path, 'rb') as f:
raw = f.read()
result = chardet.detect(raw)
encoding = result['encoding'] or 'utf-8' # 猜不到就用 utf-8 兜底
print(f"检测到编码: {encoding} (置信度: {result['confidence']:.0%})")
return raw.decode(encoding, errors='replace')
text = read_any_file('mystery.txt')
print(text)3.4 实战:批量转换文件编码为 UTF-8
import chardet
from pathlib import Path
def convert_to_utf8(src_dir):
"""把目录下所有 GBK 文件转成 UTF-8"""
for file in Path(src_dir).glob('*.txt'):
raw = file.read_bytes()
result = chardet.detect(raw)
if result['encoding'] and result['encoding'].upper() not in ('UTF-8', 'ASCII'):
text = raw.decode(result['encoding'])
file.write_text(text, encoding='utf-8')
print(f'{file.name}: {result["encoding"]} → UTF-8')
else:
print(f'{file.name}: 已是 UTF-8,跳过')
convert_to_utf8('documents')3.5 常见误区
误区 1:chardet 的检测结果 100% 准确。
真相:chardet 是统计猜测,不是魔法。它的准确性取决于:
- 文本长度:文本越短越难猜。几个字节的内容可能猜错;
- 语言特征:GBK 和 GB2312 高度相似,经常互相误判(但 GBK 兼容 GB2312,所以问题不大)。
对策:置信度低于 0.7 时要人工确认;关键业务提供编码手动指定入口。
误区 2:检测出编码后直接 decode() 就万事大吉。
真相:即使编码猜对,文件中也可能有少量损坏的字节。建议加 errors='replace' 参数,把无法解码的字节替换为 `` 而不是直接报错:
text = raw.decode(encoding, errors='replace')误区 3:chardet 能检测加密或压缩的数据。
真相:chardet 只能检测纯文本的编码。ZIP、加壳数据、二进制文件(图片等)检测结果是毫无意义的。
四、psutil:系统资源的"体检医生"
4.1 模块简介
psutil(process and system utilities)是一个跨平台的系统监控库,能获取:
- CPU 使用率、核心数、频率
- 内存占用
- 磁盘空间和 IO
- 网络流量
- 进程列表和进程详情
它统一了 Windows、Linux、macOS 的差异——同一套代码,三个系统都能跑。
pip install psutil生活化理解:psutil 就是把 Windows 的"任务管理器"和 Linux 的 top 命令搬进了 Python,而且是用代码可以读取的结构化数据。
典型应用:服务器监控告警、资源统计报表、自动清理僵死进程、运维巡检脚本。
4.2 CPU 信息
import psutil
# 逻辑核心数(含超线程)
print(psutil.cpu_count()) # 16
# 物理核心数
print(psutil.cpu_count(logical=False)) # 8
# CPU 使用率(百分比)
# interval=1 表示采样 1 秒,越长时间越准
print(psutil.cpu_percent(interval=1)) # 23.5
# 每个核心的使用率
print(psutil.cpu_percent(interval=1, percpu=True))
# [20.0, 35.0, 15.5, ...]
# CPU 频率(MHz)
freq = psutil.cpu_freq()
print(f'当前频率: {freq.current} MHz, 最大: {freq.max} MHz')注意:cpu_percent(interval=0) 或 interval=None 比较的是"上次调用到现在"的平均值,第一次调用通常返回 0 或无意义。推荐显式传 interval=1。
4.3 内存信息
import psutil
mem = psutil.virtual_memory()
print(f'总内存: {mem.total / 1024**3:.1f} GB')
print(f'已用: {mem.used / 1024**3:.1f} GB')
print(f'可用: {mem.available / 1024**3:.1f} GB')
print(f'使用率: {mem.percent}%')
# 交换分区(虚拟内存)
swap = psutil.swap_memory()
print(f'Swap 使用率: {swap.percent}%')free vs available 的区别(容易混淆):
free:完全没被碰过的内存;available:实际可用内存(包括系统缓存中可以随时释放的部分)。
判断内存够不够,看 available,别看 free。Linux 会把空闲内存拿去做磁盘缓存,所以 free 经常很小,这是正常的。
4.4 磁盘信息
import psutil
# 磁盘分区
for part in psutil.disk_partitions():
print(part.device, part.mountpoint, part.fstype)
# C:\ C:\ ntfs
# D:\ D:\ ntfs
# 某个分区的使用情况
usage = psutil.disk_usage('C:\\')
print(f'总容量: {usage.total / 1024**3:.1f} GB')
print(f'已用: {usage.used / 1024**3:.1f} GB')
print(f'使用率: {usage.percent}%')
# 磁盘 IO 统计
io = psutil.disk_io_counters()
print(f'读取: {io.read_bytes / 1024**2:.0f} MB, 写入: {io.write_bytes / 1024**2:.0f} MB')4.5 网络信息
import psutil
# 网络 IO 统计(自开机以来)
net = psutil.net_io_counters()
print(f'发送: {net.bytes_sent / 1024**2:.1f} MB')
print(f'接收: {net.bytes_recv / 1024**2:.1f} MB')
# 计算实时网速:采样两次求差值
import time
n1 = psutil.net_io_counters()
time.sleep(1)
n2 = psutil.net_io_counters()
speed = (n2.bytes_recv - n1.bytes_recv) / 1024 # KB/s
print(f'当前下载速度: {speed:.1f} KB/s')4.6 进程管理
这是 psutil 最强大的部分:
import psutil
# 所有进程的 PID 列表
print(psutil.pids())
# 遍历所有进程
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent']):
print(proc.info)
# {'pid': 1, 'name': 'System', 'cpu_percent': 0.0}
# ...
# 操作单个进程
p = psutil.Process(1234) # 按 PID 获取
print(p.name()) # 进程名
print(p.exe()) # 可执行文件路径
print(p.cwd()) # 工作目录
print(p.status()) # 运行状态(running/sleeping/zombie)
print(p.cpu_percent()) # CPU 占用
print(p.memory_info()) # 内存占用
print(p.create_time()) # 创建时间(时间戳)
# 结束进程
p.terminate() # 温和结束(相当于点"关闭")
p.kill() # 强制杀死(相当于"结束任务")4.7 实战案例 1:资源监控告警
import psutil
import time
def monitor(threshold_cpu=90, threshold_mem=90, interval=60):
"""持续监控,资源超标时告警"""
while True:
cpu = psutil.cpu_percent(interval=1)
mem = psutil.virtual_memory().percent
if cpu > threshold_cpu:
print(f'[告警] CPU 使用率过高: {cpu}%')
if mem > threshold_mem:
print(f'[告警] 内存使用率过高: {mem}%')
time.sleep(interval)
# monitor() # 取消注释即可启动监控4.8 实战案例 2:揪出"资源大户"
import psutil
def top_memory_processes(n=10):
"""找出内存占用最高的 n 个进程"""
procs = []
for p in psutil.process_iter(['pid', 'name', 'memory_info']):
try:
procs.append(p.info)
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass # 进程可能刚好退出,或权限不足
# 按内存排序
procs.sort(key=lambda x: x['memory_info'].rss, reverse=True)
print(f'{"PID":>8} {"内存(MB)":>10} 进程名')
for p in procs[:n]:
mb = p['memory_info'].rss / 1024**2
print(f"{p['pid']:>8} {mb:>10.1f} {p['name']}")
top_memory_processes()4.9 实战案例 3:清理僵死进程
import psutil
def kill_zombies():
"""查找并清理僵尸进程"""
for p in psutil.process_iter(['pid', 'name', 'status']):
if p.info['status'] == psutil.STATUS_ZOMBIE:
print(f"发现僵尸进程: {p.info['name']} (PID={p.info['pid']})")
try:
p.kill()
except psutil.NoSuchProcess:
pass4.10 其他实用信息
import psutil
from datetime import datetime
# 开机时间
boot = datetime.fromtimestamp(psutil.boot_time())
print(f'开机时间: {boot}')
# 电池信息(笔记本)
battery = psutil.sensors_battery()
if battery:
print(f'电量: {battery.percent}%, 充电中: {battery.power_plugged}')4.11 常见误区
误区 1:遍历进程时不处理异常。
真相:进程是"活的"——你遍历的瞬间,某个进程可能刚好退出,或者你没有权限访问它。process_iter 循环中必须捕获 NoSuchProcess 和 AccessDenied:
for p in psutil.process_iter():
try:
print(p.name())
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue误区 2:memory_info().rss 在不同系统含义完全一致。
真相:rss(常驻内存)在 Windows 和 Linux 上的统计口径略有差异。跨平台对比时知道大概量级即可,不要抠小数点。
误区 3:Windows 上想用 psutil 杀系统进程。
真相:杀进程需要相应权限。Windows 上需要"以管理员身份运行",Linux 上需要 sudo,否则会抛 AccessDenied。
五、四大模块速查表
| 模块 | 一句话定位 | 安装命令 | 核心 API |
|---|---|---|---|
| Pillow | 图像处理车间 | pip install Pillow | Image.open()、resize、thumbnail、crop、filter |
| requests | 网络快递员 | pip install requests | get、post、Session、r.json()、r.raise_for_status() |
| chardet | 编码侦探 | pip install chardet | chardet.detect(bytes) |
| psutil | 体检医生 | pip install psutil | cpu_percent、virtual_memory、disk_usage、process_iter |
注意导入名与安装名的差异:
pip install Pillow → from PIL import Image
pip install requests → import requests
pip install chardet → import chardet
pip install psutil → import psutil六、综合实战:一句话串联四大模块
最后用一个"网站截图监控"的例子,把四个模块串起来(伪代码示意):
import requests
import chardet
import psutil
from PIL import Image
from io import BytesIO
# 1. psutil:先检查本机资源是否健康
if psutil.virtual_memory().percent > 90:
print('内存不足,暂停任务')
# 2. requests:下载一张网络图片
r = requests.get('https://example.com/banner.jpg', timeout=10)
r.raise_for_status()
# 3. chardet:检测一个文本接口返回内容的编码
text_resp = requests.get('https://example.com/api/notice')
encoding = chardet.detect(text_resp.content)['encoding']
notice = text_resp.content.decode(encoding or 'utf-8')
# 4. Pillow:处理下载的图片
im = Image.open(BytesIO(r.content))
im.thumbnail((400, 400))
im.save('banner_thumb.jpg')
print('任务完成:', notice)七、小结
| 核心知识点 | 一句话总结 |
|---|---|
| pip | 第三方模块的安装入口,务必配合 venv 使用 |
| Pillow | 装的是 Pillow,导入的是 PIL;thumbnail 原地改,resize 返回新对象 |
| requests | 必设 timeout,用 Session 保持登录和连接复用,二进制用 content |
| chardet | 检测是"猜"不是"算",短文本不准,decode 加 errors='replace' |
| psutil | 遍历进程必捕获异常,内存看 available 别看 free |
记住三句话:
- 图像找 Pillow,上网找 requests,乱码找 chardet,监控找 psutil;
- 所有网络请求必须设超时,所有进程遍历必须捕获异常;
- 第三方模块虽好用,但先查标准库——能零依赖解决的,别引入新依赖。
参考说明
本文内容基于各模块官方文档及廖雪峰 Python 教程的"常用第三方模块"章节重新整理和扩充,示例代码适用于 Pillow 10+、requests 2.31+、chardet 5+、psutil 5.9+。