一、背景
前面已经整理了 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,不建议只靠正则,后续可以使用 BeautifulSoup 或 lxml。
十、collections:增强容器
collections 提供了一些比普通 dict、list 更方便的容器。
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)]
这些工具在处理批量参数组合、测试数据、排列组合时比较有用。
十二、一个简单综合示例
下面写一个小脚本,实现:
- 从命令行传入日志目录
- 遍历
.log文件 - 使用正则提取错误码
- 使用
Counter统计错误码出现次数 - 使用
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
这个例子里同时用到了:
argparseloggingrecollections.Counterpathlib.Path
这些标准库组合起来,已经可以写出很多实用脚本。
十三、总结
这一篇整理了几个常用 Python 标准库。
需要重点记住:
os适合处理操作系统相关操作sys适合查看解释器、模块路径和运行参数pathlib更适合现代 Python 路径处理datetime处理日期时间logging用来替代大量printsubprocess用来执行外部命令argparse用来编写命令行工具re用于正则匹配、提取、替换collections提供增强容器itertools提供迭代处理工具
掌握这些标准库后,很多日常脚本和小工具就可以不依赖第三方库直接完成。