news 2026/10/22 12:51:57

Python中常用脚本集锦分享

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python中常用脚本集锦分享

前言


日常办公和开发里,真正天天用得到的往往不是复杂的框架,而是那种十几行就能解决一个小问题的脚本。它们不追求工程化,只追求「复制过去改两个路径就能用」。本文选的四个场景都很朴素:批量重命名文件、统计目录占用、文本按行去重、从名单里随机抽签。


需要先说明一个常见误解:很多人把「脚本」理解成「能自动干活的程序」,于是把注意力放在功能上,忽略了脚本同样要处理边界情况——文件被占用、编码不是 UTF-8、路径里有空格、抽签数量超过名单长度。这些才是脚本跑一半报错的主要原因。


下文的示例都以 Python 3 为基准,全部是标准库,不依赖任何第三方包。涉及较新语法的地方会注明版本。每个例子都保持十几行的规模,方便直接拼进你自己的工具箱。


另外要强调:本文只讲正当的本地文件与文本处理。凡是涉及探测、规避、攻击他人系统的脚本都不属于「常用脚本」的范畴,本文也不会提供。


一、批量重命名文件


最常见的需求是给一批文件统一加前缀或去掉冗余前缀。用pathlib比os.listdir更直观,因为它把路径当作对象,取名字、改名字都是方法调用。


# 适用于 Python 3.9+(用到了 str.removeprefix)
from pathlib import Path

def rename_add_prefix(folder, prefix):
"""给目录下所有文件加统一前缀(已加过的不重复加)"""
for p in sorted(Path(folder).iterdir()):
if p.is_file() and not p.name.startswith(prefix):
p.rename(p.with_name(prefix + p.name))

def rename_strip_prefix(folder, prefix):
"""去掉统一前缀"""
for p in sorted(Path(folder).iterdir()):
if p.is_file() and p.name.startswith(prefix):
p.rename(p.with_name(p.name.removeprefix(prefix)))

str.removeprefix()是 Python 3.9 引入的。如果你还在 3.8,要写成p.name[len(prefix):],但那会无条件截断,前缀不匹配时反而会切错,所以更稳妥的旧写法是:


# 适用于 Python 3.8
from pathlib import Path

def rename_strip_prefix_38(folder, prefix):
for p in sorted(Path(folder).iterdir()):
if p.is_file() and p.name.startswith(prefix):
new_name = p.name[len(prefix):]
p.rename(p.with_name(new_name))

Path.rename()是原地改名,返回改名后的新Path对象,原对象不会自动更新。改名要一个一个来,批量改名不存在「一次性原子提交」,所以脚本中途失败时,目录会处于改了一半的状态。稳妥的做法是先用一个「试运行」开关只打印不执行,确认无误再真正跑。


二、统计目录占用与文件类型分布


想知道某个目录里哪些类型的文件最多、总共占了多少空间,用rglob("*")递归遍历即可。注意rglob会同时返回目录,必须用is_file()过滤。


# 适用于 Python 3.8+
from pathlib import Path
from collections import Counter

def dir_stats(root):
counter = Counter()
total_bytes = 0
for p in Path(root).rglob("*"):
if p.is_file():
counter[p.suffix.lower() or "(无扩展名)"] += 1
total_bytes += p.stat().st_size
return counter, total_bytes

if __name__ == "__main__":
kinds, total = dir_stats(".")
for ext, n in kinds.most_common(10):
print(f"{ext:>12} {n:>6} 个")
print(f"合计 {total / 1024 / 1024:.2f} MB")

Counter.most_common(n)返回出现次数最多的前 n 项,返回的是列表,元素是(键, 计数)元组。p.stat().st_size是字节数,按 1024 进制换算成 MB 只是便于阅读。


这里有个容易忽略的点:rglob遇到没有权限的子目录会抛PermissionError。如果你要扫描的目录有这种情况,应当在循环里try/except PermissionError跳过,而不是让整个脚本崩掉。


三、文本按行去重


处理日志、导出名单时,经常需要把重复行删掉。关键决策是「按什么算重复」:整行原样比较,还是去掉首尾空白后比较。两种语义不同,必须在函数名或参数里说清。


# 适用于 Python 3.8+
def dedup_lines(src, dst, strip_blank=True):
"""按行去重;strip_blank=True 时忽略首尾空白后再比较,
且丢弃空行。保持原有顺序。"""
seen = set()
with open(src, encoding="utf-8") as fin, \
open(dst, "w", encoding="utf-8", newline="\n") as fout:
for line in fin:
key = line.strip() if strip_blank else line.rstrip("\n")
if strip_blank and not key:
continue
if key in seen:
continue
seen.add(key)
fout.write(line if line.endswith("\n") else line + "\n")

要点有三个。第一,open()必须显式写encoding="utf-8",否则在 Windows 上默认用本地代码页解码,遇到 UTF-8 文件里的中文会直接UnicodeDecodeError;这是跨平台脚本最常见的乱码来源。第二,用set判重是 O(1) 的,比每次遍历列表快得多,且随着行数增长不会退化。第三,输出时统一用newline="\n",避免 Windows 上被自动写成\r\n。


如果文件特别大(比如几 GB),把seen全放内存里不现实,这时应当改成先做外部排序再相邻去重——但那是另一个量级的需求,十几行的脚本不承担这个责任。


四、从名单里随机抽签


抽奖、分组、随机派单都用到它。标准库的random.sample(population, k)是无放回抽样,返回长度为 k 的新列表,原列表不变。


# 适用于 Python 3.8+
import random

def draw_winners(names, k, seed=None):
"""从 names 中无放回抽取 k 个"""
if k < 0:
raise ValueError("抽取数量不能为负")
if k > len(names):
raise ValueError(
f"要抽 {k} 个,但名单只有 {len(names)} 个"
)
rng = random.Random(seed)
return rng.sample(names, k)

用random.Random(seed)建一个独立实例,而不是直接用模块级函数,好处是随机状态互不干扰:同一个 seed 必然得到同一结果,便于复现和留痕;同时不会影响程序里别处正在用的全局随机序列。


必须点明一个边界:random模块不是密码学安全的,它的输出可被预测,绝不能用来生成令牌、密码、验证码或抽奖中的真金白银凭据。凡是需要「防作弊」的随机,要用secrets模块(secrets.choice、secrets.randbelow等),它以操作系统提供的密码学安全随机源为基础。选错了模块,抽出来的奖可能被人反推。


常见坑点



  • ❌ 直接open("a.txt")不写encoding,在 Windows 上读 UTF-8 中文文件报UnicodeDecodeError。


✅ 一律写open("a.txt", encoding="utf-8"),写文件时再按需加newline="\n"。



  • ❌ 用for p in Path(folder).rglob("*")后直接对p调stat(),目录没权限时整脚本崩溃。


✅ 先if p.is_file()过滤,并对PermissionError单独捕获跳过。



  • ❌ 边遍历os.listdir()边对同一目录做改名/删除,结果漏处理或重复处理。


✅ 先把列表转成list(...)再循环,或改用sorted(...)生成静态快照。



  • ❌ 用random.random()或random.shuffle()生成密码、令牌、抽奖凭据。


✅ 安全场景用secrets模块;random只用于可复现的模拟与演示。



  • ❌ 以为list.sort()返回排好序的新列表,写出data = data.sort(),结果data变成None。


✅list.sort()是原地排序返回None;需要新列表用sorted(data)。



  • ❌ 把str.removeprefix()当 3.8 也能用,脚本在旧环境直接AttributeError。


✅ 3.9 起才有removeprefix/removesuffix;3.8 环境用切片或显式startswith判后再截。



  • ❌ 去重时用key = line却期望忽略大小写和空白,去重结果不符合预期。


✅ 明确去重口径:是否strip()、是否lower(),并写进函数参数名或文档字符串。


总结




脚本关键 API最需要注意的边界



批量重命名Path.iterdir、Path.rename、str.removeprefix中途失败会改一半,先试运行

目录统计Path.rglob、Counter.most_common、stat().st_size无权限目录抛PermissionError

文本去重set、open(encoding=...)编码必须显式指定,去重口径要明确

随机抽签random.Random.samplerandom不安全,凭据要用secrets



写工具箱脚本的诀窍不是把功能堆得多,而是把每个小脚本的边界想清楚:输入从哪来、编码是什么、失败时会不会污染现场。四个脚本加起来不到一百行,但把「显式编码、过滤目录、安全随机」这几条守住,它们就能长期稳定地被复用。




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

静脉曲张治疗新思路:超声血流动力学指导下的热消融与CHIVA融合术

静脉曲张治疗这几年走到一个很有意思的节点&#xff1a;热消融凭借微创和恢复快成了很多医院的主力术式&#xff0c;而CHIVA这种“保留静脉”的老思路一直在另一边被一小部分医生坚定守着。两边争论了很久&#xff0c;好像“闭合”和“保留”天然对立。但临床做多了你会发现&am…

作者头像 李华
网站建设 2026/10/20 17:01:50

三相变压器核心知识全解析:磁路、连接组别与不对称运行

1. 三相变压器到底在讲什么&#xff1a;从单相到三相的思维跃迁很多人复习电机学&#xff0c;看到三相变压器这一章就开始头疼。单相变压器还没彻底搞明白&#xff0c;突然就冒出连接组别、标幺值、不对称运行这些概念&#xff0c;公式一大堆&#xff0c;符号满天飞。我当初学这…

作者头像 李华
网站建设 2026/10/12 4:40:09

t3code:编码规范、智能补全与提交流程一体化的轻量工具箱

t3code&#xff1a;我把编码规范、智能补全与提交流程&#xff0c;收进了一个代号为“三代目”的工具箱如果你常在开发者社区泡着&#xff0c;最近应该没少刷到“t3code”这个代号。几个技术群里都在传&#xff0c;说是某个团队内部孵化的编码效率工具&#xff0c;也有人说它是…

作者头像 李华
网站建设 2026/10/20 13:16:55

927张痤疮JPG图训练YOLOv8检测模型:小样本数据实战指南

简介&#xff1a;痤疮数据集专为YOLOv8目标检测模型训练而设计&#xff0c;包含九百二十七张JPG格式皮肤影像及配套标注&#xff0c;面向计算机视觉开发者、医疗AI研究者和皮肤科智能诊断相关项目。资源共一千八百五十五个文件&#xff0c;其中九百二十七张原始图像对应九百二十…

作者头像 李华
网站建设 2026/10/17 17:36:13

数据库系统原理课程设计报告:从选题到落地的完整拆解

简介&#xff1a;这份数据库系统原理课程设计报告面向计算机相关专业学生与数据库初学者&#xff0c;围绕一家批发企业的信息化管理需求&#xff0c;完整呈现从需求分析到数据库运行维护的设计流程。内容涵盖商品、订单、零售商、供应商与商品类型五类核心信息的实体建模&#…

作者头像 李华