Python 常用标准库整理


一、背景

前面已经整理了 Python 基础语法、函数、模块、文件、异常、面向对象、线程、数据库、JSON,以及 pip 和第三方库安装。

不过在实际写 Python 脚本时,并不是所有事情都需要安装第三方库。

Python 自带了很多标准库,安装 Python 后就可以直接使用。

这一篇整理几个日常使用频率比较高的标准库:

os
sys
pathlib
datetime
logging
subprocess
argparse
re
collections
itertools

这些库可以解决文件路径、系统参数、日期时间、日志、执行外部命令、命令行参数、正则匹配、常用容器增强和迭代处理等问题。

二、os:操作系统相关功能

os 模块用于处理操作系统相关功能,比如环境变量、目录创建、路径判断、文件删除等。

1. 查看当前工作目录

import os

print(os.getcwd())

os.getcwd() 返回当前程序运行时所在目录。

注意它不一定等于当前 .py 文件所在目录。

2. 创建目录

import os

os.makedirs("data/logs", exist_ok=True)

exist_ok=True 表示目录已经存在时不报错。

这个参数很常用。

3. 判断文件或目录是否存在

import os

print(os.path.exists("data"))
print(os.path.isfile("app.log"))
print(os.path.isdir("data"))

4. 读取环境变量

import os

mysql_host = os.getenv("MYSQL_HOST", "127.0.0.1")
print(mysql_host)

os.getenv() 第二个参数是默认值。

配置数据库地址、接口地址、运行环境时,经常会用环境变量。

5. 遍历目录

import os

for root, dirs, files in os.walk("data"):
    for file_name in files:
        print(os.path.join(root, file_name))

os.walk() 适合做文件批量处理。

三、sys:解释器和运行参数

sys 模块主要和 Python 解释器本身有关。

1. 查看 Python 可执行文件

import sys

print(sys.executable)

排查虚拟环境时,这个命令很有用。

如果代码导入不到某个模块,可以先看当前实际使用的是哪个 Python。

2. 查看模块搜索路径

import sys

for path in sys.path:
    print(path)

sys.path 决定了 import 时从哪些目录查找模块。

3. 获取命令行参数

import sys

print(sys.argv)

例如执行:

python demo.py input.txt output.txt

sys.argv 大概是:

["demo.py", "input.txt", "output.txt"]

不过如果命令行参数比较多,建议使用后面介绍的 argparse

4. 退出程序

import sys

sys.exit(1)

0 通常表示正常退出,非 0 表示异常退出。

四、pathlib:更好用的路径处理

早期 Python 代码中经常使用 os.path 处理路径。

现在更推荐使用 pathlib

pathlib 把路径当成对象来处理,写起来更清楚。

1. 创建 Path 对象

from pathlib import Path

path = Path("data") / "logs" / "app.log"

print(path)

使用 / 拼接路径,比字符串拼接更安全。

2. 获取当前文件目录

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent

print(BASE_DIR)

项目中经常用这种方式定位项目根目录。

3. 创建目录和写文件

from pathlib import Path

log_dir = Path("data/logs")
log_dir.mkdir(parents=True, exist_ok=True)

file_path = log_dir / "app.log"
file_path.write_text("hello\n", encoding="utf-8")

4. 读文件

from pathlib import Path

file_path = Path("data/logs/app.log")
content = file_path.read_text(encoding="utf-8")

print(content)

5. 遍历文件

from pathlib import Path

for file_path in Path("data").glob("*.txt"):
    print(file_path)

递归遍历:

for file_path in Path("data").rglob("*.txt"):
    print(file_path)

五、datetime:日期和时间

datetime 用于处理日期、时间、时间差和格式化。

1. 获取当前时间

from datetime import datetime

now = datetime.now()
print(now)

2. 格式化时间

from datetime import datetime

now = datetime.now()

print(now.strftime("%Y-%m-%d %H:%M:%S"))

常用格式:

格式 含义
%Y 四位年份
%m 两位月份
%d 两位日期
%H 24 小时制小时
%M 分钟
%S

3. 字符串转时间

from datetime import datetime

text = "2024-01-23 20:30:00"
dt = datetime.strptime(text, "%Y-%m-%d %H:%M:%S")

print(dt)

4. 时间加减

from datetime import datetime, timedelta

now = datetime.now()

print(now + timedelta(days=1))
print(now - timedelta(hours=2))

5. 获取日期

from datetime import date

today = date.today()
print(today)

六、logging:日志记录

写脚本时,不建议大量使用 print() 代替日志。

logging 可以记录日志级别、时间、模块名,也可以输出到文件。

1. 最简单用法

import logging

logging.basicConfig(level=logging.INFO)

logging.info("程序开始")
logging.warning("这是 warning 日志")
logging.error("这是 error 日志")

常见日志级别:

级别 说明
DEBUG 调试信息
INFO 普通运行信息
WARNING 警告
ERROR 错误
CRITICAL 严重错误

2. 设置日志格式

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s %(message)s",
)

logger = logging.getLogger(__name__)

logger.info("hello logging")

3. 输出日志到文件

import logging

logging.basicConfig(
    filename="app.log",
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
)

logging.info("写入日志文件")

实际项目中,日志单独写一篇也值得展开。这里先记住:普通脚本可以从 logging.basicConfig() 开始。

七、subprocess:执行外部命令

subprocess 用来在 Python 中执行系统命令。

1. 执行命令

import subprocess

result = subprocess.run(["ls", "-l"], capture_output=True, text=True)

print(result.returncode)
print(result.stdout)
print(result.stderr)

参数说明:

参数 说明
capture_output=True 捕获标准输出和错误输出
text=True 输出按字符串处理
returncode 命令退出码
stdout 标准输出
stderr 错误输出

2. 命令失败时抛出异常

import subprocess

subprocess.run(["ls", "not_exists"], check=True)

如果命令退出码不是 0,会抛出 subprocess.CalledProcessError

3. 不要随意使用 shell=True

import subprocess

subprocess.run("ls -l", shell=True)

shell=True 可以执行完整 shell 命令,但是如果命令中包含用户输入,就可能带来安全风险。

更推荐写成列表:

subprocess.run(["ls", "-l"])

八、argparse:命令行参数解析

如果要写一个命令行脚本,建议使用 argparse

例如写一个简单脚本 demo.py

import argparse


parser = argparse.ArgumentParser(description="文件处理脚本")
parser.add_argument("--input", required=True, help="输入文件")
parser.add_argument("--output", required=True, help="输出文件")
parser.add_argument("--debug", action="store_true", help="是否开启调试模式")

args = parser.parse_args()

print(args.input)
print(args.output)
print(args.debug)

执行:

python demo.py --input a.txt --output b.txt --debug

查看帮助:

python demo.py --help

argparse 会自动生成帮助信息,也会在参数缺失时提示错误。

这比直接解析 sys.argv 更稳。

九、re:正则表达式

re 用于正则匹配、提取、替换。

1. 判断是否匹配

import re

text = "error code: 500"

result = re.search(r"\d+", text)

if result:
    print(result.group())

输出:

500

2. 提取多个结果

import re

text = "id=100, id=200, id=300"

ids = re.findall(r"id=(\d+)", text)

print(ids)

输出:

['100', '200', '300']

3. 替换

import re

text = "phone=13812345678"
new_text = re.sub(r"\d{11}", "***********", text)

print(new_text)

4. 常用正则符号

符号 含义
. 任意字符
\d 数字
\w 字母、数字、下划线
\s 空白字符
+ 一次或多次
* 零次或多次
? 零次或一次
{n} 出现 n 次
() 分组
[] 字符集合

正则很适合日志解析、文本提取、简单格式校验。

如果要解析 HTML,不建议只靠正则,后续可以使用 BeautifulSouplxml

十、collections:增强容器

collections 提供了一些比普通 dictlist 更方便的容器。

1. Counter 计数

from collections import Counter

words = ["spark", "hive", "spark", "flink"]

counter = Counter(words)

print(counter)
print(counter.most_common(2))

输出:

Counter({'spark': 2, 'hive': 1, 'flink': 1})
[('spark', 2), ('hive', 1)]

2. defaultdict

defaultdict 可以给不存在的 key 自动创建默认值。

from collections import defaultdict

groups = defaultdict(list)

groups["bigdata"].append("spark")
groups["bigdata"].append("hive")
groups["python"].append("requests")

print(groups)

如果使用普通字典,需要先判断 key 是否存在。

3. deque

deque 是双端队列,适合从两端添加或删除元素。

from collections import deque

queue = deque()

queue.append("a")
queue.append("b")
queue.appendleft("start")

print(queue.popleft())
print(queue.pop())

4. namedtuple

namedtuple 可以创建带字段名的元组。

from collections import namedtuple

User = namedtuple("User", ["name", "age"])

user = User("xiaoming", 18)

print(user.name)
print(user.age)

不过在较新的代码中,很多场景也可以使用 dataclass

十一、itertools:迭代工具

itertools 提供了很多迭代处理工具。

1. count

from itertools import count

for i in count(1):
    print(i)

    if i >= 5:
        break

count() 会一直递增,所以要注意终止条件。

2. chain

把多个可迭代对象串起来。

from itertools import chain

data = chain([1, 2], [3, 4], [5])

print(list(data))

输出:

[1, 2, 3, 4, 5]

3. groupby

groupby() 可以按连续相同的 key 分组。

from itertools import groupby

items = [
    {"type": "a", "name": "n1"},
    {"type": "a", "name": "n2"},
    {"type": "b", "name": "n3"},
]

for key, group in groupby(items, key=lambda item: item["type"]):
    print(key, list(group))

需要注意:groupby() 只会把连续相同 key 的数据分到一起。

如果原始数据没有排序,通常先排序:

items = sorted(items, key=lambda item: item["type"])

4. combinations 和 product

组合:

from itertools import combinations

print(list(combinations([1, 2, 3], 2)))

输出:

[(1, 2), (1, 3), (2, 3)]

笛卡尔积:

from itertools import product

print(list(product(["a", "b"], [1, 2])))

输出:

[('a', 1), ('a', 2), ('b', 1), ('b', 2)]

这些工具在处理批量参数组合、测试数据、排列组合时比较有用。

十二、一个简单综合示例

下面写一个小脚本,实现:

  1. 从命令行传入日志目录
  2. 遍历 .log 文件
  3. 使用正则提取错误码
  4. 使用 Counter 统计错误码出现次数
  5. 使用 logging 输出处理过程
import argparse
import logging
import re
from collections import Counter
from pathlib import Path


logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
)


def parse_error_codes(log_dir):
    counter = Counter()
    pattern = re.compile(r"error_code=(\d+)")

    for file_path in Path(log_dir).rglob("*.log"):
        logging.info("处理文件: %s", file_path)

        for line in file_path.read_text(encoding="utf-8").splitlines():
            match = pattern.search(line)

            if match:
                counter[match.group(1)] += 1

    return counter


def main():
    parser = argparse.ArgumentParser(description="统计日志错误码")
    parser.add_argument("--log-dir", required=True, help="日志目录")

    args = parser.parse_args()

    result = parse_error_codes(args.log_dir)

    for code, count in result.most_common():
        print(code, count)


if __name__ == "__main__":
    main()

执行:

python stat_error.py --log-dir ./logs

这个例子里同时用到了:

  1. argparse
  2. logging
  3. re
  4. collections.Counter
  5. pathlib.Path

这些标准库组合起来,已经可以写出很多实用脚本。

十三、总结

这一篇整理了几个常用 Python 标准库。

需要重点记住:

  1. os 适合处理操作系统相关操作
  2. sys 适合查看解释器、模块路径和运行参数
  3. pathlib 更适合现代 Python 路径处理
  4. datetime 处理日期时间
  5. logging 用来替代大量 print
  6. subprocess 用来执行外部命令
  7. argparse 用来编写命令行工具
  8. re 用于正则匹配、提取、替换
  9. collections 提供增强容器
  10. itertools 提供迭代处理工具

掌握这些标准库后,很多日常脚本和小工具就可以不依赖第三方库直接完成。


文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录