TL;DR
- 拖慢你的不是不会算法,是每天发生 20 次的
ImportError、手写 __init__、os.path 拼路径——这些微小摩擦才是真正的效率杀手。
- 8 个技巧全来自 Python 标准库或一行
pip install,不需要学新框架、不需要重构项目,今天看了明天就能用。
python -m 告别导入报错、pathlib 替代 os.path、dataclass 省样板代码、rich 美化调试——把认知资源留给值得思考的问题。
8 个能立刻用上的 Python 开发效率技巧——从 python -m 告别导入报错,到 rich 让调试输出一目了然,再到 dataclasses 省掉一半样板代码。每个技巧都附带可直接复制的代码示例。
01 效果先行
先看一个对比。这是大多数 Python 初学者写的代码:
import os
# 手动拼路径,丑且容易出错
data_dir = os.path.join("project", "data", "2024", "raw")
config_file = os.path.join(data_dir, "config.json")
# 手动计数器
i = 0
items = ["requests", "httpx", "aiohttp"]
for item in items:
print(f"{i}: {item}")
i += 1
# 手写 __init__,纯体力活
class APIConfig:
def __init__(self, url, timeout, retries):
self.url = url
self.timeout = timeout
self.retries = retries
def __repr__(self):
return f"APIConfig(url={self.url}, timeout={self.timeout}, retries={self.retries})"
这是改完之后的:
from pathlib import Path
data_dir = Path("project") / "data" / "2024" / "raw"
config_file = data_dir / "config.json"
items = ["requests", "httpx", "aiohttp"]
for i, item in enumerate(items):
print(f"{i}: {item}")
from dataclasses import dataclass
@dataclass
class APIConfig:
url: str
timeout: int
retries: int
少了快一半代码,可读性反而更高。下面逐个拆解这些技巧。
02 场景定义
我写了 4 年多 Python,发现一个规律:真正拖慢开发速度的,不是你不会某个算法,而是一堆“小不爽”在消耗你。
比如:
- 脚本跑起来报
ImportError,查了半天发现是路径写法不对
- 打印了一坨调试信息,眼睛看花了才找到关键字段
- 每次新建数据类都要手写
__init__,像在做填空题
- 用
os.path 拼路径,代码看着像正则表达式
这些不是大问题。但当它们每天出现 20 次,一周就是 140 次微小摩擦。
下面这 8 个技巧,每一个解决一类“小不爽”。不需要学新框架,不需要重构整个项目——今天看了明天就能用。
03 环境搭建
本文所有示例基于 Python 3.9+,大部分特性 3.7+ 就支持。唯一需要额外安装的库是 rich:
pip install rich
其余都是 Python 标准库自带,不用装任何东西。
04 核心技巧
技巧 1:用 python -m 运行脚本,告别导入报错
新手习惯这样跑脚本:
python app/main.py
项目一大,迟早会撞上这个报错:
ImportError: attempted relative import with no known parent package
换一种方式:
python -m app.main
Python 会把你的代码当作正经模块来执行,导入路径自动对齐项目根目录。越是多人协作、多层目录的项目,这个习惯越值钱。
我见过一个实习生因为这个报错 debug 了两个小时,最后改了一行命令就好了。
技巧 2:用 rich 让调试输出像 IDE 一样清晰
标准 print() 够用,但丑。当你调试嵌套字典或复杂 JSON 时,满屏黑白文字很难一眼定位问题。
from rich import print
data = {
"user": "小王",
"requests": 142,
"errors": [
{"code": 503, "msg": "Service Unavailable", "count": 12},
{"code": 429, "msg": "Rate Limited", "count": 7},
],
}
print(data)
输出自动带上语法高亮和格式化缩进,嵌套结构一目了然。
再加一行:
from rich.traceback import install
install()
之后所有异常的回溯信息都会变成彩色分层的格式。这看起来像“锦上添花”,实际上可读的调试信息直接降低认知负荷——而认知负荷正是隐藏的生产力杀手。
技巧 3:用 pathlib 替代 os.path
老项目中到处都是这种写法:
import os
config_path = os.path.join("project", "config", "app.yaml")
if os.path.exists(config_path):
content = open(config_path).read()
pathlib 是 Python 3.4 就有的标准库,但很多人一直没用起来:
from pathlib import Path
config_path = Path("project") / "config" / "app.yaml"
if config_path.exists():
content = config_path.read_text()
用 / 拼路径比 os.path.join() 直观太多。而且 Path 对象自带 read_text()、write_text()、read_bytes()、glob() 等方法,不用再调 open() 了。
# 遍历目录下所有 CSV 文件
for csv_file in Path("data").glob("*.csv"):
print(csv_file.read_text())
你一旦用习惯,再回去看 os.path 会觉得像在用 Java 写文件操作。
技巧 4:用 dataclasses 消灭样板代码
如果你的类主要就是存数据,手写 __init__ 纯属体力劳动:
from dataclasses import dataclass
@dataclass
class LLMConfig:
model: str = "claude-sonnet-4-6"
temperature: float = 0.7
max_tokens: int = 4096
三行搞定。自动获得 __init__、__repr__、__eq__。
这在 API 开发、配置管理、ETL 管道里特别实用——省掉的不只是打字,更是心智开销。你一眼就能看清这个类有哪些字段、什么类型、默认值是多少。
技巧 5:enumerate() 和列表推导式
还在这样写?
i = 0
for name in names:
print(i, name)
i += 1
Python 标准库十年前就替你解决了:
for i, name in enumerate(names):
print(i, name)
同理,把 4 行映射写成 1 行:
# 之前
results = []
for n in numbers:
results.append(n * 2)
# 之后
results = [n * 2 for n in numbers]
但记住一句话:如果你的推导式看起来像被熬夜巫师写出来的数学证明,换回普通 for 循环。六个月后的你会感谢现在的你。
技巧 6:永远用 if __name__ == "__main__" 保护入口
这不是“高级技巧”,但大量 Python 开发者跳过它:
def main():
# 你的脚本逻辑
process_data()
generate_report()
if __name__ == "__main__":
main()
为什么重要?因为早晚有一天你会:
- 把这个文件 import 到别处复用
- 给它写测试
- 重构时把功能拆到不同模块
没有这个守卫,import 时脚本可能意外执行——触发 API 调用、写数据库、发邮件。凌晨两点被报警叫醒,通常就是因为这种“小疏忽”。
别问我怎么知道的。
技巧 7:用 time.perf_counter() 做性能测试
很多人测代码性能顺手写:
import time
start = time.time()
# ... 你的代码 ...
print(time.time() - start)
time.time() 是看钟用的,不适合 benchmark。它精度不够,而且受系统时间调整的影响。
正确做法:
from time import perf_counter
start = perf_counter()
# ... 你的代码 ...
elapsed = perf_counter() - start
print(f"耗时: {elapsed:.4f} 秒")
perf_counter() 专为性能测量设计,精度更高、不受系统时间跳变影响。你在优化 API 响应、数据处理管道时,这 0.001 秒的精度差别会非常关键——尤其是当那段代码在生产环境跑了 40 万次。
技巧 8:用 watchdog 实现热重载
“改一行代码 → 切到终端 → 重新运行 → 看结果 → 再改一行”这个循环,每天至少重复几十次。
pip install watchdog
然后:
watchmedo auto-restart --patterns="*.py" -- python your_script.py
保存文件后脚本自动重启。尤其在调试 API 调用或数据处理流程时,这个体验像开挂一样。
等你习惯了这个节奏,手动重跑脚本会感觉像在用 2006 年的翻盖手机。
05 踩坑提醒
这 8 个技巧都不难,但有几点要注意:
python -m 的路径写法:用点分隔而非斜杠。app/main.py → app.main,写错了会报 No module named。
dataclasses 的可变默认值陷阱:不要在字段默认值里直接用 [] 或 {},用 field(default_factory=list)。
- 列表推导式不要写太深:超过 2 层嵌套或带多个
if 条件时,果断换普通循环。同事会感谢你的。
perf_counter() 的返回值:单位是秒,但起点不保证是某个固定时间点——只用来算差值。
06 完整代码 + 下一步
把以上技巧串起来的日常开发模板:
"""日常 Python 脚本模板 —— 每个新项目从这里开始"""
from pathlib import Path
from time import perf_counter
from dataclasses import dataclass
from rich import print
from rich.traceback import install
install() # 全局美化异常回溯
@dataclass
class Config:
data_dir: str = "data"
output_dir: str = "output"
def process_files(config: Config) -> list[Path]:
"""读取 data_dir 下所有 CSV,返回文件路径列表"""
data_path = Path(config.data_dir)
if not data_path.exists():
raise FileNotFoundError(f"目录不存在: {config.data_dir}")
return list(data_path.glob("*.csv"))
def main():
start = perf_counter()
config = Config()
files = process_files(config)
for i, f in enumerate(files):
print(f"[{i}] {f.name}")
print(f"\n[green]处理完成,共 {len(files)} 个文件,耗时 {perf_counter() - start:.3f}s[/green]")
if __name__ == "__main__":
main()
把这个模板保存下来,下次新建 Python 脚本时直接复制,省掉环境初始化的“冷启动”时间。
下一步可以玩什么?
- 把
rich 的进度条(rich.progress)接入你的数据处理循环
- 用
watchdog 监听文件目录,自动触发数据处理流程
- 把
dataclasses 换成 pydantic.BaseModel,给配置类加上自动校验
这些技巧本身很小。但每天少踩的坑、少写的样板代码、少耗的认知资源,一个月下来就是质变。
真正的效率不是“敲键盘更快”——是把精力留给值得思考的问题。如果你也有自己总结的效率秘笈,不妨来 云栈社区 和大家一起切磋。