书籍翻译技术知识点详解
书籍翻译项目 - 技术知识点详解
项目名称: PDF书籍自动翻译系统
作者: MrSponge
创建时间: 2026-05-05
版本: v1.0
目录
- Python 基础语法与特性
- 面向对象编程 (OOP)
- 模块与包管理
- 核心第三方库详解
- 项目架构与设计模式
- 文件操作与路径处理
- 日志记录系统
- 配置管理
- 命令行参数处理
- 异常处理
- 类型提示 (Type Hints)
- 文件编码与字符处理
1. Python 基础语法与特性
1.1 文件编码声明
# -*- coding: utf-8 -*-
知识点:
- Python 2 需要显式声明文件编码,Python 3 默认使用 UTF-8
- 放在文件第一行或第二行
- 确保中文注释和字符串正常显示
1.2 多行字符串 (Docstrings)
"""
----------------------------------------
@Author : MrSponge
@Time : 2026-05-05 16:09:01
@Version : v1.0
@Description: TODO - 书籍翻译项目启动文件
----------------------------------------
"""
知识点:
- 使用三个引号
"""或'''创建多行字符串 - 通常用于模块、类、函数的文档说明
- 可以通过
__doc__属性访问
1.3 f-string 格式化字符串
log.info(f'开始翻译文件:{file_path}')
log.info(f'输出格式:{file_format}')
知识点:
- Python 3.6+ 引入的格式化方式
- 在字符串前加
f或F - 使用
{}包裹变量或表达式 - 性能优于
%和.format()
示例:
name = "Python"
version = 3.9
print(f'{name} {version}') # 输出: Python 3.9
print(f'{name.upper()}') # 输出: PYTHON
1.4 条件表达式 (三元运算符)
file_format = args.file_format if args.file_format else config['common'].get('file_format', 'PDF')
语法: 值1 if 条件 else 值2
等价于:
if args.file_format:
file_format = args.file_format
else:
file_format = config['common'].get('file_format', 'PDF')
1.5 链式比较
if page_index < len(self.book.pages) - 1:
知识点:
- Python 支持
a < b < c这样的链式比较 - 等价于
a < b and b < c
1.6 列表推导式
cleaned_lines = [line.strip() for line in lines if line.strip()]
知识点:
- 简洁的列表创建方式
- 语法:
[表达式 for 元素 in 可迭代对象 if 条件] - 比传统 for 循环更快
示例:
# 传统方式
squares = []
for x in range(10):
squares.append(x**2)
# 列表推导式
squares = [x**2 for x in range(10)]
1.7 字符串方法
常用方法:
# 分割字符串
lines = raw_text.splitlines() # 按行分割
# 去除空白字符
line.strip() # 去除首尾空白
line.lstrip() # 去除左侧空白
line.rstrip() # 去除右侧空白
# 查找子串
subfix = path[path.rindex('.'):] # 从右侧查找 '.' 的位置
# 替换字符串
raw_text = raw_text.replace(cell, '', 1) # 替换第一次出现的内容
# 连接列表
cleaned_text = '\n'.join(cleaned_lines)
# 大小写转换
if out_file_format.lower() == 'pdf': # 转小写
1.8 布尔判断
if raw_text: # 非空字符串为 True
if tables: # 非空列表为 True
if file_path: # 非 None 且非空为 True
if not file_path.lower().endswith('.pdf'): # 取反
知识点:
- Python 中的"真值测试"规则:
False,None,0,"",[],{},set()等视为 False- 其他值视为 True
1.9 上下文管理器 (with 语句)
with open(out_file_path, 'w', encoding='utf-8') as f:
f.write(content)
with pdfplumber.open(pdf_file) as pdf:
pages = pdf.pages
知识点:
- 自动管理资源的获取和释放
- 即使发生异常也会正确关闭资源
- 需要对象实现
__enter__()和__exit__()方法
2. 面向对象编程 (OOP)
2.1 类定义与初始化
class FileWriter:
"""
文件写入类
"""
def __init__(self, book: Book):
self.book = book
知识点:
__init__()是构造函数,创建对象时自动调用self代表实例本身,必须作为第一个参数- 类名使用大驼峰命名法 (PascalCase)
2.2 类的方法类型
实例方法 (最常用):
def save_pdf(self, out_file_path: str):
# 使用 self 访问实例属性
pass
知识点:
- 第一个参数必须是
self - 可以访问和修改实例属性
2.3 属性访问
class PDFTranslator:
def __init__(self, model: Model):
self.model = model # 公共属性
self._book = None # 受保护属性 (约定)
self.__private = None # 私有属性 (名称改写)
知识点:
self.attribute- 公共属性,外部可访问self._attribute- 受保护属性,约定不直接访问self.__attribute- 私有属性,会被改写为_ClassName__attribute
2.4 类型注解
def __init__(self, book: Book):
self.book = book
def save_pdf(self, out_file_path: str) -> None:
pass
知识点:
- Python 3.5+ 支持类型提示
参数: 类型声明参数类型-> 返回类型声明返回值类型- 只是提示,不强制检查
2.5 组合模式
class PDFTranslator:
def __init__(self, model: Model):
self.model = model # 组合 Model 对象
self.writer = FileWriter() # 组合 FileWriter 对象
知识点:
- 一个类包含其他类的实例
- 实现"has-a"关系 (翻译器有模型、有写入器)
- 区别于继承的"is-a"关系
2.6 枚举类 (Enum)
from enum import Enum
class ContentType(Enum):
TEXT = 1
TABLE = 2
IMAGE = 3
知识点:
- 定义一组常量
- 提高代码可读性和可维护性
- 防止无效值
使用:
if content.content_type == ContentType.TEXT:
# 处理文本
3. 模块与包管理
3.1 导入语句
绝对导入:
from ai_model.siliconflow_model import SiliconflowModel
from translator.book_translator import PDFTranslator
相对导入:
from .ai_model.model import Model
from ..book.book import Book
知识点:
from module import name- 导入特定名称import module- 导入整个模块as可以给导入起别名
3.2 包结构
book_translate/
├── __init__.py # 标记为包
├── ai_model/
│ ├── __init__.py
│ └── model.py
├── book/
│ ├── __init__.py
│ └── book.py
└── translator/
├── __init__.py
└── pdf_parser.py
知识点:
__init__.py使目录成为 Python 包- 可以包含包的初始化代码
- Python 3.3+ 支持隐式命名空间包 (可以没有
__init__.py)
3.3 模块导入路径
import sys
import os
# 添加项目根目录到 sys.path
sys.path.append('/path/to/project')
知识点:
- Python 按
sys.path列表搜索模块 - 当前目录 (
.) 在sys.path中 - 使用
PYTHONPATH环境变量添加路径
3.4 __main__ 模块
if __name__ == '__main__':
# 当直接运行此文件时执行
main()
知识点:
__name__是内置变量- 直接运行时值为
'__main__' - 被导入时值为模块名
- 用于编写可执行脚本和可导入模块
4. 核心第三方库详解
4.1 pdfplumber - PDF 解析库
安装: pip install pdfplumber
基本用法:
import pdfplumber
with pdfplumber.open('file.pdf') as pdf:
# 获取所有页面
pages = pdf.pages
print(f'总页数: {len(pages)}')
# 遍历每一页
for page in pages:
# 提取文本
text = page.extract_text()
print(text)
# 提取表格
tables = page.extract_tables()
for table in tables:
# table 是二维列表
for row in table:
for cell in row:
print(cell)
重要方法:
| 方法 | 说明 | 返回类型 |
|---|---|---|
pdfplumber.open(path) |
打开 PDF 文件 | PDF 对象 |
pdf.pages |
获取所有页面 | 列表 |
page.extract_text() |
提取页面文本 | str |
page.extract_tables() |
提取页面表格 | List[List[List[str]]] |
项目中的应用:
with pdfplumber.open(pdf_file) as pdf:
# 获取指定页数
if pages is None:
pages_arr = pdf.pages
else:
pages_arr = pdf.pages[:pages] # 切片获取前 n 页
for pdf_page in pages_arr:
raw_text = pdf_page.extract_text()
tables = pdf_page.extract_tables()
4.2 reportlab - PDF 生成库
安装: pip install reportlab
核心模块:
4.2.1 SimpleDocTemplate - 文档模板
from reportlab.platypus import SimpleDocTemplate
from reportlab.lib import pagesizes
doc = SimpleDocTemplate(
'output.pdf', # 文件名
pagesize=pagesizes.letter, # 页面大小: letter, A4, A3 等
leftMargin=72, # 左边距 (1 英寸 = 72 点)
rightMargin=72, # 右边距
topMargin=72, # 上边距
bottomMargin=72 # 下边距
)
常用页面大小:
pagesizes.letter- 美国信纸 (612x792 点)pagesizes.A4- A4 纸 (595x842 点)pagesizes.A3- A3 纸 (842x1190 点)
4.2.2 Paragraph - 段落
from reportlab.platypus import Paragraph
from reportlab.lib.styles import ParagraphStyle
# 创建样式
style = ParagraphStyle(
name='SimSun', # 样式名称
fontName='SimSun', # 字体名称
fontSize=10, # 字体大小 (点)
leading=14, # 行间距
spaceBefore=6, # 段前间距
spaceAfter=6, # 段后间距
leftIndent=0, # 左缩进
rightIndent=0, # 右缩进
firstLineIndent=0 # 首行缩进
)
# 创建段落
paragraph = Paragraph(
text='这是段落内容',
style=style
)
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
name |
str | 样式名称,用于引用 |
fontName |
str | 字体名称 (需先注册) |
fontSize |
int/float | 字体大小,单位点 (1 点 ≈ 0.35mm) |
leading |
int/float | 行间距,通常比 fontSize 大 20-40% |
spaceBefore |
int/float | 段落前的空白 |
spaceAfter |
int/float | 段落后的空白 |
leftIndent |
int/float | 左缩进 |
rightIndent |
int/float | 右缩进 |
firstLineIndent |
int/float | 首行缩进 |
4.2.3 Table - 表格
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
# 准备数据 (二维列表)
data = [
['表头1', '表头2', '表头3'],
['数据1', '数据2', '数据3'],
['数据4', '数据5', '数据6']
]
# 创建表格
table = Table(
data=data, # 表格数据
colWidths=[100, 150, 120], # 列宽列表
rowHeights=20 # 行高 (可选)
)
# 设置样式
table_style = TableStyle([
# 格式: ('命令', (开始列, 开始行), (结束列, 结束行), 参数)
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#4472C4')),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONT', (0, 0), (-1, -1), 'SimSun'),
('FONTSIZE', (0, 0), (-1, -1), 11),
('TOPPADDING', (0, 0), (-1, -1), 8),
('BOTTOMPADDING', (0, 0), (-1, -1), 8),
('LEFTPADDING', (0, 0), (-1, -1), 12),
('RIGHTPADDING', (0, 0), (-1, -1), 12),
('BACKGROUND', (0, 1), (-1, -1), colors.HexColor('#D9E1F2')),
('GRID', (0, 0), (-1, -1), 1, colors.HexColor('#8EA9DB')),
('LINEBELOW', (0, 0), (-1, 0), 2, colors.HexColor('#2F5496')),
])
table.setStyle(table_style)
坐标系统:
(0, 0)- 左上角 (第一列, 第一行)(-1, 0)- 右上角 (最后一列, 第一行)(0, -1)- 左下角 (第一列, 最后一行)(-1, -1)- 右下角 (最后一列, 最后一行)
常用命令:
| 命令 | 说明 | 参数 |
|---|---|---|
BACKGROUND |
背景色 | 颜色对象 |
TEXTCOLOR |
文字颜色 | 颜色对象 |
ALIGN |
对齐方式 | 'LEFT', 'CENTER', 'RIGHT' |
FONT |
字体 | 字体名称字符串 |
FONTSIZE |
字体大小 | 数字 (点) |
TOPPADDING |
上内边距 | 数字 (点) |
BOTTOMPADDING |
下内边距 | 数字 (点) |
LEFTPADDING |
左内边距 | 数字 (点) |
RIGHTPADDING |
右内边距 | 数字 (点) |
GRID |
网格线 | 线宽, 颜色 |
LINEBELOW |
下边框线 | 线宽, 颜色 |
BOX |
外边框 | 线宽, 颜色 |
VALIGN |
垂直对齐 | 'TOP', 'MIDDLE', 'BOTTOM' |
4.2.4 PageBreak - 分页符
from reportlab.platypus import PageBreak
pdf_data.append(PageBreak()) # 添加分页符
4.2.5 字体注册
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# 注册 TrueType 字体
pdfmetrics.registerFont(TTFont('SimSun', 'simsun.ttc'))
pdfmetrics.registerFont(TTFont('SimHei', 'simhei.ttf'))
支持的中文字体:
- 宋体:
simsun.ttc - 黑体:
simhei.ttf - 微软雅黑:
msyh.ttc - 楷体:
simkai.ttf
4.2.6 构建文档
pdf_data = [] # 内容列表
# 添加内容
pdf_data.append(paragraph)
pdf_data.append(table)
pdf_data.append(PageBreak())
# 构建 PDF
doc.build(pdf_data)
项目中的应用:
# 完整流程
pdf_data = []
for page in self.book.pages:
for content in page.contents:
if content.content_type == ContentType.TEXT:
paragraph = Paragraph(text=content.translation, style=style)
pdf_data.append(paragraph)
elif content.content_type == ContentType.TABLE:
table = Table(data=table_data, colWidths=[120] * num_columns)
table.setStyle(table_style)
pdf_data.append(table)
# 添加分页符 (除最后一页)
if page != self.book.pages[-1]:
pdf_data.append(PageBreak())
doc.build(pdf_data)
4.3 pandas - 数据处理库
安装: pip install pandas
核心数据结构:
4.3.1 DataFrame
import pandas as pd
# 从列表创建 DataFrame
data = [
['苹果', '红色', 1.20],
['香蕉', '黄色', 0.50]
]
columns = ['水果', '颜色', '价格']
df = pd.DataFrame(data, columns=columns)
print(df)
输出:
水果 颜色 价格
0 苹果 红色 1.20
1 香蕉 黄色 0.50
常用属性和方法:
| 属性/方法 | 说明 | 返回类型 |
|---|---|---|
df.columns |
列名 | Index 对象 |
df.values |
数据数组 | numpy.ndarray |
df.values.tolist() |
转换为嵌套列表 | List[List] |
df.head(n) |
前 n 行 | DataFrame |
df.tail(n) |
后 n 行 | DataFrame |
df.shape |
行列数 | Tuple[int, int] |
df.info() |
数据信息 | None |
项目中的应用:
# 将表格数据转换为 DataFrame
translation_df = pd.DataFrame(table_data[1:], columns=table_data[0])
# 转换回列表用于 reportlab
table_data = df.values.tolist()
4.4 loguru - 日志库
安装: pip install loguru
基本用法:
from loguru import logger
logger.debug('调试信息')
logger.info('普通信息')
logger.warning('警告信息')
logger.error('错误信息')
logger.critical('严重错误')
日志级别 (从低到高):
TRACE- 跟踪DEBUG- 调试INFO- 信息SUCCESS- 成功WARNING- 警告ERROR- 错误CRITICAL- 严重
自定义配置:
from loguru import logger
import sys
# 清除默认处理器
logger.remove()
# 添加控制台输出
logger.add(
sys.stdout, # 输出到标准输出
level='DEBUG', # 日志级别
format="<green>{time:YYYYMMDD HH:mm:ss}</green> | "
"{process.name} | "
"{thread.name} | "
"<cyan>{module}</cyan>.<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
"<level>{level}</level>: "
"<level>{message}</level>",
colorize=True # 启用颜色
)
# 添加文件输出
logger.add(
'app.log', # 日志文件
level='DEBUG', # 日志级别
encoding='UTF-8', # 编码
rotation='10 MB', # 文件大小限制
retention=20, # 保留天数
format='{time:YYYYMMDD HH:mm:ss} - {message}'
)
格式化参数:
| 参数 | 说明 | 示例 |
|---|---|---|
{time} |
时间 | 20260507 22:44:42 |
{level} |
日志级别 | INFO |
{message} |
日志消息 | 开始翻译文件 |
{module} |
模块名 | main |
{function} |
函数名 | <module> |
{line} |
行号 | 43 |
{process.name} |
进程名 | MainProcess |
{thread.name} |
线程名 | MainThread |
高级功能:
# 自动捕获异常
@logger.catch
def risky_function():
return 1 / 0
# 记录异常
try:
risky_function()
except Exception as e:
logger.exception(e) # 记录异常堆栈
# 日志轮转
logger.add('app.log', rotation='1 week') # 每周轮转
logger.add('app.log', rotation='100 MB') # 每 100MB 轮转
logger.add('app.log', rotation='12:00') # 每天中午轮转
# 日志保留
logger.add('app.log', retention='30 days') # 保留 30 天
logger.add('app.log', retention='1 year') # 保留 1 年
项目中的封装:
class MyLogger:
def __init__(self):
self.logger = logger
self.logger.remove()
# 控制台输出
self.logger.add(sys.stdout, level='DEBUG', format=...)
# 文件输出
self.logger.add(log_file_path, level='DEBUG', rotation='10 MB', retention=20)
def get_logger(self):
return self.logger
log = MyLogger().get_logger()
# 使用
log.info('信息')
log.debug('调试')
log.error('错误')
4.5 PyYAML - YAML 配置文件解析
安装: pip install pyyaml
YAML 文件示例 (config.yaml):
siliconflow:
model: deepseek-ai/DeepSeek-V3
api_key: sk-xxxxxxxx
base_url: https://api.siliconflow.cn
common:
book: test/test.pdf
file_format: PDF
读取配置:
import yaml
# 读取 YAML 文件
with open('config.yaml', 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
# 访问配置
model = config['siliconflow']['model']
api_key = config['siliconflow']['api_key']
file_format = config['common']['file_format']
# 安全访问 (使用 get 方法)
file_format = config['common'].get('file_format', 'PDF') # 默认值为 'PDF'
常用方法:
| 方法 | 说明 |
|---|---|
yaml.safe_load(stream) |
安全加载 YAML (推荐) |
yaml.load(stream, Loader=yaml.FullLoader) |
加载 YAML (不推荐, 有安全风险) |
yaml.dump(data) |
将 Python 对象转为 YAML 字符串 |
yaml.safe_dump(data) |
安全转储 |
项目中的封装:
class LoaderConfig:
def __init__(self, config_path):
self.config_path = config_path
def load_config(self):
with open(self.config_path, 'r', encoding='utf-8') as f:
return yaml.safe_load(f)
# 使用
config = LoaderConfig('config.yaml').load_config()
4.6 argparse - 命令行参数解析
基本用法:
import argparse
parser = argparse.ArgumentParser(description='书籍自动翻译器')
# 添加参数
parser.add_argument('--book', type=str, help='需要翻译的书籍路径')
parser.add_argument('--file_format', type=str, default='PDF', help='输出格式')
parser.add_argument('--model_type', type=str, required=True,
choices=['SiliconFlow', 'GLMModel'],
help='选择模型')
# 解析参数
args = parser.parse_args()
# 访问参数
book_path = args.book
file_format = args.file_format
model_type = args.model_type
常用参数:
parser.add_argument(
'--name', # 参数名 (长选项)
'-n', # 短选项 (可选)
type=str, # 参数类型 (str, int, float, bool)
default='value', # 默认值
required=True, # 是否必需
choices=['A', 'B'], # 可选值列表
help='参数说明', # 帮助信息
action='store_true' # 特殊动作 (不需要值)
)
action 参数:
| 值 | 说明 | 示例 |
|---|---|---|
store |
存储值 (默认) | --file pdf → args.file = 'pdf' |
store_true |
存储 True | --verbose → args.verbose = True |
store_false |
存储 False | --quiet → args.quiet = False |
append |
追加到列表 | --tag a --tag b → ['a', 'b'] |
count |
计数 | -v -v -v → 3 |
项目中的应用:
class ArgumentUtils:
def __init__(self):
self.parser = argparse.ArgumentParser(description='书籍自动翻译器')
self.parser.add_argument('--model_name', type=str, default='deepseek-ai/DeepSeek-V3')
self.parser.add_argument('--api_key', type=str, default='')
self.parser.add_argument('--config', type=str, default='config.yaml')
self.parser.add_argument('--model_type', type=str, required=True,
choices=['SiliconFlow', 'GLMModel'])
self.parser.add_argument('--book', type=str)
self.parser.add_argument('--file_format', type=str, default='PDF')
def parse_args(self):
args = self.parser.parse_args()
# 自定义验证逻辑
if args.model_type == 'SiliconFlow' and not args.model_name and not args.api_key:
self.parser.error('请指定模型名称和API密钥')
return args
帮助信息:
python main.py --help
5. 项目架构与设计模式
5.1 项目结构
book_translate/
├── main.py # 入口文件
├── ai_model/ # AI 模型模块
│ ├── model.py # 模型基类
│ └── siliconflow_model.py # SiliconFlow 实现
├── book/ # 书籍数据模型
│ ├── book.py # Book 类
│ ├── page.py # Page 类
│ └── content.py # Content 类
├── translator/ # 翻译器模块
│ ├── pdf_parser.py # PDF 解析器
│ ├── book_translator.py # 翻译控制器
│ └── file_writer.py # 文件写入器
├── utils/ # 工具模块
│ ├── argument_utils.py # 命令行参数
│ ├── loader_config.py # 配置加载
│ ├── log_utils.py # 日志工具
│ └── exceptions.py # 自定义异常
├── fonts/ # 字体文件
│ └── simsun.ttc
├── test/ # 测试文件
│ └── test.pdf
└── logs/ # 日志目录
└── translation.log
5.2 设计模式
5.2.1 策略模式 (Strategy Pattern)
应用场景: 不同输出格式的处理
class FileWriter:
def save_book(self, out_file_path, out_file_format):
if out_file_format.lower() == 'pdf':
self.save_pdf(out_file_path)
elif out_file_format.lower() == 'markdown':
self.save_markdown(out_file_path)
elif out_file_format.lower() == 'docx':
self.save_docx(out_file_path)
优点:
- 易于扩展新的输出格式
- 符合开闭原则 (对扩展开放,对修改封闭)
5.2.2 工厂方法模式 (Factory Method)
应用场景: 创建不同的模型实例
if args.model_type == 'SiliconFlow':
model = SiliconflowModel(model_name, api_key, api_base)
else:
model = GLMModel(model_name, api_key, api_base)
5.2.3 模板方法模式 (Template Method)
应用场景: PDF 解析流程
def parse_pdf(pdf_file, pages=None):
book = Book(pdf_file)
with pdfplumber.open(pdf_file) as pdf:
for pdf_page in pdf.pages:
page = Page()
# 提取文本
text = pdf_page.extract_text()
# 提取表格
tables = pdf_page.extract_tables()
# 处理内容
page.add_content(text)
book.add_page(page)
return book
5.3 面向对象设计原则
单一职责原则 (SRP):
PDFParser只负责解析 PDFFileWriter只负责文件写入PDFTranslator只负责翻译流程
依赖倒置原则 (DIP):
PDFTranslator依赖抽象的Model接口- 不依赖具体的
SiliconflowModel实现
开闭原则 (OCP):
- 添加新的模型只需创建新的类
- 不需要修改现有代码
6. 文件操作与路径处理
6.1 os 模块
常用函数:
import os
# 路径操作
os.path.dirname(__file__) # 获取文件所在目录
os.path.abspath(__file__) # 获取文件绝对路径
os.path.join(dir1, dir2, 'file.txt') # 路径拼接
os.path.exists(path) # 检查路径是否存在
os.path.isfile(path) # 检查是否为文件
os.path.isdir(path) # 检查是否为目录
os.path.basename(path) # 获取文件名
os.path.splitext(path) # 分离文件名和扩展名
# 目录操作
os.mkdir(path) # 创建目录
os.makedirs(path, exist_ok=True) # 递归创建目录
os.listdir(path) # 列出目录内容
os.chdir(path) # 切换工作目录
os.getcwd() # 获取当前工作目录
# 文件操作
os.remove(path) # 删除文件
os.rename(old, new) # 重命名
os.path.getsize(path) # 获取文件大小
项目中的应用:
# 获取当前文件所在目录
current_dir = os.path.dirname(os.path.abspath(__file__))
# 构建字体文件路径
font_path = os.path.join(current_dir, '..', 'fonts', 'simsun.ttc')
# 创建日志目录
if not os.path.exists(log_dir):
os.mkdir(log_dir)
# 获取文件名
filename = os.path.basename(self.book.book_path)
# 检查文件扩展名
if not file_path.lower().endswith('.pdf'):
log.error('目前只支持PDF格式的文件')
6.2 文件读写
读取文件:
# 方式 1: with 语句 (推荐)
with open('config.yaml', 'r', encoding='utf-8') as f:
content = f.read() # 读取全部内容
# lines = f.readlines() # 读取所有行
# line = f.readline() # 读取一行
# 方式 2: 手动关闭 (不推荐)
f = open('file.txt', 'r', encoding='utf-8')
try:
content = f.read()
finally:
f.close()
写入文件:
# 写入模式
with open('output.md', 'w', encoding='utf-8') as f:
f.write('# 标题\n')
f.write('内容\n')
# 追加模式
with open('output.md', 'a', encoding='utf-8') as f:
f.write('追加内容\n')
文件模式:
| 模式 | 说明 |
|---|---|
'r' |
只读 (默认) |
'w' |
写入 (覆盖) |
'a' |
追加 |
'b' |
二进制模式 (与以上组合) |
'+' |
读写模式 |
6.3 路径处理技巧
字符串替换:
# 替换文件扩展名
subfix = path[path.rindex('.'):] # 获取扩展名: '.pdf'
new_path = path.replace(subfix, '_translated.md')
项目中的应用:
# 生成输出文件路径
if out_file_path is None:
subfix = self.book.book_path[self.book.book_path.rindex('.'):]
out_file_path = self.book.book_path.replace(subfix, '_translated.pdf')
7. 日志记录系统
7.1 日志的重要性
- 记录程序运行状态
- 调试问题
- 监控系统健康
- 审计和安全
7.2 日志级别选择
log.trace('最详细的调试信息') # 开发阶段使用
log.debug('调试信息') # 开发阶段使用
log.info('普通信息') # 生产环境使用
log.warning('警告') # 潜在问题
log.error('错误') # 错误但程序继续运行
log.critical('严重错误') # 程序可能无法继续
7.3 最佳实践
# ❌ 不好: 使用 print
print('开始翻译')
# ✅ 好: 使用日志
log.info('开始翻译文件:{file_path}')
# ❌ 不好: 吞掉异常
try:
result = process()
except:
pass
# ✅ 好: 记录异常
try:
result = process()
except Exception as e:
log.error(f'处理失败: {e}')
log.exception(e) # 记录堆栈信息
8. 配置管理
8.1 为什么需要配置文件
- 分离代码和配置
- 便于修改参数
- 支持不同环境 (开发/测试/生产)
- 避免硬编码敏感信息
8.2 YAML 配置示例
# config.yaml
siliconflow:
model: deepseek-ai/DeepSeek-V3
api_key: ${SILICONFLOW_API_KEY} # 环境变量
base_url: https://api.siliconflow.cn
common:
book: test/test.pdf
file_format: PDF
timeout: 60
logging:
level: DEBUG
file: translation.log
8.3 配置优先级
# 1. 命令行参数 (最高优先级)
# 2. 配置文件
# 3. 代码默认值 (最低优先级)
file_format = args.file_format if args.file_format else config['common'].get('file_format', 'PDF')
9. 命令行参数处理
9.1 参数设计原则
必需参数:
parser.add_argument('--model_type', type=str, required=True,
choices=['SiliconFlow', 'GLMModel'])
可选参数 (有默认值):
parser.add_argument('--file_format', type=str, default='PDF')
标志参数 (布尔值):
parser.add_argument('--verbose', action='store_true',
help='启用详细输出')
9.2 参数验证
def parse_args(self):
args = self.parser.parse_args()
# 自定义验证逻辑
if args.model_type == 'SiliconFlow':
if not args.api_key:
self.parser.error('SiliconFlow 模型需要提供 API 密钥')
return args
9.3 使用示例
# 基本使用
python main.py --model_type='SiliconFlow'
# 指定文件
python main.py --model_type='SiliconFlow' --book='test.pdf'
# 指定输出格式
python main.py --model_type='SiliconFlow' --file_format='markdown'
# 查看帮助
python main.py --help
10. 异常处理
10.1 自定义异常
class PageOutRangeException(Exception):
"""页面超出范围异常"""
def __init__(self, total_pages, requested_pages):
self.total_pages = total_pages
self.requested_pages = requested_pages
super().__init__(
f'请求的页面数 {requested_pages} 超过总页数 {total_pages}'
)
使用:
if pages and pages > len(pdf.pages):
raise PageOutRangeException(len(pdf.pages), pages)
10.2 异常捕获
# 捕获特定异常
try:
result = 1 / 0
except ZeroDivisionError as e:
log.error(f'除零错误: {e}')
# 捕获所有异常
try:
process()
except Exception as e:
log.error(f'未知错误: {e}')
log.exception(e) # 记录完整堆栈
# finally 块 (始终执行)
try:
f = open('file.txt')
content = f.read()
finally:
f.close() # 确保文件关闭
10.3 装饰器捕获异常
from loguru import logger
@logger.catch
def risky_function():
return 1 / 0
# 相当于
def risky_function():
try:
return 1 / 0
except Exception as e:
logger.exception(e)
return None
11. 类型提示 (Type Hints)
11.1 基本类型
def greet(name: str, age: int, height: float, is_active: bool) -> str:
return f'{name} is {age} years old'
11.2 容器类型
from typing import List, Dict, Optional, Tuple
def process_data(
items: List[str], # 字符串列表
config: Dict[str, int], # 字典
name: Optional[str] = None, # 可选参数 (可以是 None)
point: Tuple[int, int] # 元组
) -> List[int]:
return [1, 2, 3]
11.3 项目中的应用
from typing import Optional
def parse_pdf(pdf_file: str, pages: Optional[int] = None) -> Book:
"""
:param pdf_file: pdf文件路径
:param pages: 可选的,需要翻译的前n页
:return: 返回一个Book对象
"""
pass
常用类型:
| 类型 | 说明 | 示例 |
|---|---|---|
int |
整数 | age: int = 25 |
float |
浮点数 | price: float = 1.20 |
str |
字符串 | name: str = 'Python' |
bool |
布尔值 | flag: bool = True |
List[T] |
列表 | items: List[str] |
Dict[K, V] |
字典 | config: Dict[str, int] |
Optional[T] |
可选类型 | name: Optional[str] |
Tuple[T, ...] |
元组 | point: Tuple[int, int] |
Any |
任意类型 | data: Any |
12. 文件编码与字符处理
12.1 文件编码
# 读取文件时指定编码
with open('file.txt', 'r', encoding='utf-8') as f:
content = f.read()
# 写入文件时指定编码
with open('file.txt', 'w', encoding='utf-8') as f:
f.write('中文内容')
常见编码:
utf-8- 通用编码 (推荐)gbk- 简体中文 (Windows)gb2312- 简体中文big5- 繁体中文
12.2 字符串处理
去除空白:
text = ' Hello World \n'
text.strip() # 'Hello World'
text.lstrip() # 'Hello World \n'
text.rstrip() # ' Hello World'
分割字符串:
# 按行分割
lines = text.splitlines()
# 按空格分割
words = text.split()
# 按指定字符分割
parts = text.split(',')
连接字符串:
# 使用 join (高效)
lines = ['line1', 'line2', 'line3']
text = '\n'.join(lines)
# 使用 f-string (推荐)
name = 'Python'
version = 3.9
text = f'{name} {version}'
12.3 列表推导式处理
# 过滤空行
lines = raw_text.splitlines()
cleaned_lines = [line.strip() for line in lines if line.strip()]
# 转换数据
data = ['1.20', '0.50', '0.80']
numbers = [float(x) for x in data]
# 嵌套列表
table = [
['苹果', '红色', '1.20'],
['香蕉', '黄色', '0.50']
]
columns = [row[0] for row in table] # ['苹果', '香蕉']
附录
A. 常用 Python 内置函数
| 函数 | 说明 | 示例 |
|---|---|---|
len() |
获取长度 | len([1,2,3]) → 3 |
type() |
获取类型 | type(123) → int |
isinstance() |
类型检查 | isinstance(123, int) → True |
str() |
转字符串 | str(123) → '123' |
int() |
转整数 | int('123') → 123 |
float() |
转浮点数 | float('1.23') → 1.23 |
list() |
转列表 | list((1,2,3)) → [1,2,3] |
dict() |
转字典 | dict(a=1) → |
range() |
生成序列 | range(3) → 0,1,2 |
enumerate() |
枚举 | enumerate(['a','b']) → (0,'a'),(1,'b') |
zip() |
压缩 | zip([1,2], ['a','b']) → (1,'a'),(2,'b') |
sorted() |
排序 | sorted([3,1,2]) → [1,2,3] |
sum() |
求和 | sum([1,2,3]) → 6 |
max() |
最大值 | max([1,2,3]) → 3 |
min() |
最小值 | min([1,2,3]) → 1 |
B. 常用字符串方法
| 方法 | 说明 |
|---|---|
strip() |
去除首尾空白 |
split() |
分割字符串 |
join() |
连接字符串 |
replace() |
替换 |
find() |
查找子串位置 |
startswith() |
是否以...开始 |
endswith() |
是否以...结束 |
upper() |
转大写 |
lower() |
转小写 |
capitalize() |
首字母大写 |
title() |
标题格式 |
format() |
格式化字符串 |
C. 常用列表方法
| 方法 | 说明 |
|---|---|
append() |
添加元素 |
extend() |
扩展列表 |
insert() |
插入元素 |
remove() |
删除元素 |
pop() |
弹出元素 |
sort() |
排序 |
reverse() |
反转 |
index() |
查找索引 |
count() |
计数 |
D. 常用字典方法
| 方法 | 说明 |
|---|---|
keys() |
获取所有键 |
values() |
获取所有值 |
items() |
获取键值对 |
get() |
获取值 (安全) |
pop() |
删除并返回值 |
update() |
更新字典 |
clear() |
清空字典 |
参考资源
官方文档
学习资源
文档版本: v1.0
最后更新: 2026-05-07
维护者: MrSponge

浙公网安备 33010602011771号