cloc是专为统计代码行数设计的跨平台工具,支持400+语言,自动排除注释、空行及字符串内换行,安装运行仅需两步:pip install cloc与cloc命令加关键参数。

用 cloc 命令行工具最省事,别手写 Python 脚本
直接调用外部工具比自己解析文件更可靠——cloc 专为统计代码行数设计,支持 400+ 种语言,自动跳过注释、空行、字符串字面量里的换行,还能识别多行注释嵌套。Python 自带的 len(open(f).readlines()) 会把注释和空行全算进去,结果严重虚高。
安装和运行只需两步:
-
pip install cloc(或用系统包管理器,如brew install cloc/apt install cloc) cloc --by-file --quiet --exclude-dir=__pycache__,venv,.git .
关键参数说明:--by-file 显示每个文件明细;--quiet 抑制进度条(适合管道或 CI);--exclude-dir 必须加,否则 venv 和 .git 会把统计拉偏好几倍。
如果必须用 Python,优先用 pathlib + tokenize,别用正则匹配
正则处理 Python 源码极易出错:三引号字符串、注释符号在字符串里、反斜杠续行都会让 re.match(r'^\s*#') 失效。Python 标准库的 tokenize 模块能真实复现解释器的词法分析过程,准确区分注释、字符串、代码行。
核心逻辑是遍历每个 .py 文件,用 tokenize.generate_tokens() 扫描所有 token,只计数类型为 tokenize.NAME 或 tokenize.NUMBER 等「实际参与执行」的 token 所在行(需去重):
from pathlib import Path
import tokenize
def count_py_lines(path):
lines = set()
with open(path, 'rb') as f:
for tok in tokenize.generate_tokens(f.readline):
if tok.type in (tokenize.NAME, tokenize.NUMBER, tokenize.OP) and tok.string.strip():
lines.add(tok.start[0])
return len(lines)
total = sum(count_py_lines(f) for f in Path(".").rglob("*.py") if "venv" not in str(f))
注意:tokenize 要求文件以二进制模式打开;tok.start[0] 是行号(从 1 开始);set 去重防止同一行多个 token 重复计数。
cloc 的 --report-file 可导出结构化结果,方便后续分析
超大代码库往往需要按模块、作者或时间维度拆分统计,cloc 默认输出是人肉可读文本,但加 --report-file=report.json 就能生成 JSON,字段包括 "language"、"code"(有效行)、"comment"、"blank"、"file" 等。你可以用 Python 直接加载做聚合:
import json
with open("report.json") as f:
data = json.load(f)
py_stats = [f for f in data["files"] if f["language"] == "Python"]
print(sum(f["code"] for f in py_stats))
常见坑:cloc 对 symlink 默认不跟随,如果代码库用了子模块或硬链接,得加 --follow-links;另外它默认不统计 .pyi 文件,要加 --include-ext=pyi 才计入。
绕不开的陷阱:Git 未跟踪的临时文件、自动生成代码、测试数据文件
统计结果失真的主因从来不是工具选错,而是没清理输入源。cloc . 会扫当前目录下所有文件,包括 __pycache__/ 下的 .pyc、IDE 生成的 .idea/、Jupyter 的 .ipynb(即使你只关心 .py)、还有 tests/data/ 里几 MB 的 JSON 测试集。
安全做法是只统计 Git 跟踪的 Python 文件:
- Linux/macOS:
git ls-files "*.py" | xargs cloc --stdin-name=*.py - Windows PowerShell:
git ls-files "*.py" | cloc --stdin-name=*.py
这样既排除了所有未提交的临时文件,又天然过滤掉被 .gitignore 屏蔽的目录(如 venv)。如果项目用了 pre-commit 或 nox,它们生成的临时环境目录也一并消失。
真正麻烦的是那些“看起来像代码、其实不是”的文件:protobuf 生成的 _pb2.py、Swagger 生成的 client、SQLAlchemy 的 models.py 里混着大段 SQL 字符串——这些得靠人工规则二次过滤,工具本身解决不了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











