找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1955

积分

0

好友

272

主题
发表于 5 天前 | 查看: 11| 回复: 0

你是否也有这样的习惯:编写 Python 代码时,第一反应是“我自己写一个工具函数”,而不是先想想“标准库里是不是已经有现成的了”?

我曾经也是如此,直到有一天回顾项目代码,发现自己写了三个版本的“递归遍历文件夹”,两个“重试装饰器”,还有一堆手动拼接 URL、计算时间差的零散函数,看着都让人头疼。

因此,今天我们就秉持“别再重复造轮子”的理念,深入聊聊 Python 标准库里 10 个非常实用的内置模块。它们无需任何额外安装,直接 import 即可使用。以后当你再想实现某个功能时,不妨先问自己一句:Python 自己是不是已经提供了?

1) os:与操作系统交互的“门面”

日常开发中,诸如创建文件夹、删除文件、读取环境变量、切换工作目录等操作,很多人的第一反应是自己拼接路径、手动判断。

其实,绝大部分需求用几行 os 模块的代码就能优雅解决。

import os

# 获取环境变量,并提供默认值
db_url = os.getenv("DB_URL", "sqlite:///default.db")

# 确保目录存在,避免重复创建报错
log_dir = "logs"
os.makedirs(log_dir, exist_ok=True)

# 递归遍历目录下的所有文件
for root, dirs, files in os.walk("."):
    for name in files:
        if name.endswith(".py"):
            print(os.path.join(root, name))

os.makedirs(..., exist_ok=True) 这样的细节就非常贴心:即使目录已存在也不会抛出异常,省去了很多手动的 if 判断。

2) pathlib:告别手动拼接路径字符串

虽然 os.path 下的函数集合也能完成路径操作,但用多了难免显得杂乱。pathlib 模块将路径抽象为对象,操作起来更加直观和方便。

from pathlib import Path

base = Path(__file__).parent
data_dir = base / "data"
data_dir.mkdir(exist_ok=True)

log_file = data_dir / "app.log"

# 判断是否存在、读取、写入文件
if log_file.exists():
    print(log_file.read_text(encoding="utf-8"))

log_file.write_text("hello, pathlib\n", encoding="utf-8")

你看,(base / "data" / "app.log") 这种写法,比使用 "{}{}{}".format(...)os.path.join(...) 清晰易读得多,并且它能自动处理不同操作系统的路径分隔符问题。

3) collections:别再手动实现“计数器”和“默认字典”

许多人进行数据统计时,仍然在用以下方式:

d = {}
for x in data:
    if x not in d:
        d[x] = 0
    d[x] += 1

标准库直接提供了一个专为此场景设计的 Counter

from collections import Counter, defaultdict

words = ["apple", "banana", "apple", "orange", "banana", "apple"]

counter = Counter(words)
print(counter.most_common(2))  # [('apple', 3), ('banana', 2)]

# 默认字典:自动为不存在的键创建初始值
index = defaultdict(list)
for i, word in enumerate(words):
    index[word].append(i)

print(index["apple"])  # [0, 2, 5]

defaultdict(list) 这种模式在进行数据分组、构建索引或聚合时特别方便。很多人还在用 if key not in d: d[key] = [] 这样的写法,其实完全没必要。

4) itertools:构思循环逻辑前,先看看它

只要你开始编写“嵌套循环”、“排列组合”、“滑动窗口”这类逻辑,都应该先想想 itertools 模块是否已经提供了现成的“轮子”。合理利用这些工具能让你在 开源实战 中更专注于业务逻辑,而非底层实现。

import itertools as it

nums = [1, 2, 3, 4]

# 所有两两组合(不考虑顺序)
for a, b in it.combinations(nums, 2):
    print(a, b)

# 笛卡尔积
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
for c, s in it.product(colors, sizes):
    print(c, s)

# 累积求和
for s in it.accumulate(nums):
    print(s)

许多代码中那些三四层的 for 循环,其实用 product 一行就能清晰描述,逻辑也更不容易出错。

5) functools:装饰器、缓存、偏函数,一个比一个省事

这个模块不那么起眼,但它打包了几个常用的高级工具,例如用于缓存函数结果的装饰器、预先绑定部分参数的偏函数,以及用于生成排序键的函数。

最常见的就是 lru_cache。如果你编写递归函数或频繁查询配置的函数,只需添加一层缓存装饰器,性能立刻就能得到显著提升。

from functools import lru_cache, partial

@lru_cache(maxsize=128)
def fib(n: int) -> int:
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

print(fib(40))   # 有了缓存,计算速度飞快

# 偏函数:预先为函数填充部分参数
int2 = partial(int, base=2)
print(int2("1010"))  # 10

许多人为了“缓存结果”自己维护一个全局字典,还要考虑线程安全等问题。其实在多数场景下,lru_cache 装饰器就足够使用了。

6) datetime:别再用字符串和手动计算时间戳了

时间处理是容易出错的领域,手动拼接字符串或进行时间戳运算极易踩坑,尤其是在处理时区的时候。

from datetime import datetime, timedelta, timezone

# 当前时间
now = datetime.now()

# 转换为字符串
s = now.strftime("%Y-%m-%d %H:%M:%S")
print("现在:", s)

# 字符串解析为时间对象
dt = datetime.strptime("2025-01-01 12:30:00", "%Y-%m-%d %H:%M:%S")

# 计算时间差
delta = now - dt
print("相差天数:", delta.days)

# 处理时区
tz = timezone(timedelta(hours=8))  # 东八区
now_cn = datetime.now(tz=tz)
print("东八区时间:", now_cn.isoformat())

一旦场景变得复杂(跨天、跨时区、计算间隔),就不要再使用“手动计算秒数”的方式了。使用 datetime 模块能让时间处理变得清晰明了。

7) json:处理配置文件或接口数据时的首选

以前人们喜欢用 split("=") 来解析配置文件,或者手动拼接 JSON 字符串。现在基本上都会直接使用 JSON 格式,一是标准规范,二是便于与前端或其他编程语言交互。

import json
from pathlib import Path

config_path = Path("config.json")

# 写入配置
config = {
    "host": "127.0.0.1",
    "port": 8080,
    "debug": True,
    "features": ["cache", "metrics"]
}
config_path.write_text(json.dumps(config, indent=2, ensure_ascii=False), encoding="utf-8")

# 读取配置
raw = config_path.read_text(encoding="utf-8")
loaded = json.loads(raw)
print(loaded["host"], loaded["port"])

善用 indent(缩进)和 ensure_ascii(确保非ASCII字符正确显示)这些参数,能让你的配置文件瞬间变得清爽易读。

8) logging:是时候告别满屏的 print 语句了

在项目初期,随意使用 print 调试或许没问题。但随着项目规模扩大,排查问题时需要靠肉眼在日志中搜索 print 输出,那就非常痛苦了。标准库自带的 logging 模块,功能足够强大,能满足很长一段时间的需求。

import logging
from pathlib import Path

log_file = Path("app.log")

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(name)s - %(message)s",
    handlers=[
        logging.FileHandler(log_file, encoding="utf-8"),
        logging.StreamHandler()
    ]
)

logger = logging.getLogger("demo")

logger.info("服务启动了")
logger.warning("这个配置有点奇怪:%s", {"debug": True})
logger.error("出错了", exc_info=True)

具备日志级别、时间戳、输出到文件等功能后,后续接入日志分析平台或过滤关键信息都会非常方便,远比在代码中到处插入 print("here") 要可靠得多。

9) argparse:让命令行脚本瞬间专业起来

许多人编写脚本时,将参数全部硬编码在文件里,想改个路径还得打开源代码修改。更规范的做法是使用 argparse 来处理命令行参数,这能让你的脚本立刻变成一个真正的“命令行工具”。

import argparse
from pathlib import Path

def main():
    parser = argparse.ArgumentParser(description="简单的文件统计工具")
    parser.add_argument("path", help="要统计的目录")
    parser.add_argument("--ext", default=".py", help="只统计某种后缀的文件")
    args = parser.parse_args()

    base = Path(args.path)
    count = 0
    for p in base.rglob(f"*{args.ext}"):
        if p.is_file():
            count += 1

    print(f"{base} 下共有 {count} 个 {args.ext} 文件")

if __name__ == "__main__":
    main()

以后使用这个脚本时,命令就变成了:

python count_files.py . --ext .txt

一旦你开始这样编写脚本,并交给他人使用几次,你就会自然而然地延续这种模式。

10) concurrent.futures:简单的并发任务,无需从零构建

如果你自己去操作 threading.Threadmultiprocessing.Process,再加上队列、锁等机制,代码会很快变得复杂。对于许多“简单的并发任务”,例如批量网络请求或批量 IO 操作,使用 concurrent.futures 提供的线程池或进程池就足够了。这正是在 后端 & 架构 场景中处理并发问题的优雅方式之一。

from concurrent.futures import ThreadPoolExecutor, as_completed
import time
import random

def fetch(url: str) -> tuple[str, float]:
    # 模拟网络请求
    cost = random.uniform(0.1, 0.5)
    time.sleep(cost)
    return url, cost

urls = [f"https://example.com/{i}" for i in range(10)]

with ThreadPoolExecutor(max_workers=5) as executor:
    future_map = {executor.submit(fetch, url): url for url in urls}

    for future in as_completed(future_map):
        url, cost = future.result()
        print(f"{url} 用时 {cost:.3f}s")

许多诸如“写个简单爬虫”或“并发调用几个 API”的场景,使用这个模块比自己手动管理线程要省心得多。

总结

实际上,Python 标准库中能派上用场的模块远不止这 10 个,像 re(正则表达式)、subprocess(调用外部命令)、typing / dataclasses(结构化数据)、sqlite3(轻量级数据库)等也都非常实用。

但如果你能先将上述这 10 个模块运用熟练,你会逐渐发现:很多“小轮子”根本不需要你亲手打造,Python 官方已经为你精心打磨好了一套工具箱。你需要做的,就是养成在编码前先去工具箱里翻找的习惯。

下次编写脚本或功能时,不妨先停顿片刻,问自己一句:“这个功能,Python 标准库里是不是已经有现成的模块了?” 养成这个习惯,将极大提升你的开发效率与代码质量。如果你想深入探讨更多 Python 技巧或分享你的使用心得,欢迎来 云栈社区 与广大开发者交流。




上一篇:硬件设计Checklist大全:涵盖原理图与PCB评审实用表格
下一篇:深度剖析:银狐木马利用迅雷软件DLL劫持的四阶段攻击链
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-10 09:19 , Processed in 0.294419 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表