首页
/ 如何改进 CPython 文档页面:从 docs.python.org 的 "Improve this page" 入口到源码修改的完整指南

如何改进 CPython 文档页面:从 docs.python.org 的 "Improve this page" 入口到源码修改的完整指南

2026-09-06 18:21:40作者:舒璇辛Bertina

这篇指南面向所有希望为 Python 官方文档(docs.python.org)提交改进的开发者:当你阅读 CPython 手册时发现笔误、死链、过时示例或缺失说明,本文将以仓库中实际承载"Improve this page"功能的 Doc/improve-page.rst 及其配套实现为主线,讲解官方为读者提供的三条反馈通道(论坛讨论、问题跟踪器、直接编辑页面发起 Pull Request),并深入剖析这些动态链接背后由 Doc/tools/templates/customsourcelink.htmlDoc/conf.py 构成的页面渲染机制。读完本文,你将清楚一份文档意见从产生到被合入 CPython 源码的完整路径,也能在本地理解文档站点的构建方式。

一、为什么每页都有 "Improve this page":一个由文档驱动的反馈机制

在 docs.python.org 的每个 HTML 页面侧边栏底部,都有一个 "Improve this page" 链接。它并非静态写死在每一页中,而是由一套可复用的 reStructuredText 页面与 Sphinx 侧边栏模板组合而成。

CPython 仓库里有两个互为镜像的入口页面:

  • Doc/improve-page.rst:JavaScript 启用版本的页面源文件,文件头部注释明确说明"另一份面向禁用 JS 用户的版本是 improve-page-nojs.rst";
  • Doc/improve-page-nojs.rst:无 JavaScript 版本的页面源文件,注释同样要求与前者保持同步修改。

两个文件在开头都声明了 :orphan: 指令,表示它们不会出现在文档目录树(toctree)中,仅作为被其他页面或模板引用的独立页面存在。这一点从文件名也能看出——它是面向"读者此刻正在看的那一页"的通用反馈页,而不是一篇被编排进教程正文的章节。

页面中的动态占位符

Doc/improve-page.rst 的正文中有三个占位符,它们决定了这份反馈页面能"记住你从哪来":

  • PAGETITLE:你正在阅读页面的标题;
  • PAGEURL:你正在阅读页面的 URL;
  • PAGESOURCE:该页面对应的文档源码文件名(形如 library/functions.rst)。

这三个占位符会在浏览器端被一段 JavaScript 替换为真实值,从而让生成的讨论主题或 issue 自动携带完整的页面上下文,避免读者需要手工复制粘贴页面地址与标题。

双版本页面为何存在

HTML 页面中的脚注提示:"This is the JavaScript-enabled version of this page. Another version (for those with JavaScript disabled) is improve-page-nojs.rst." 也就是说,常规浏览器用户看到的是带动态脚本的版本;而当 JavaScript 被禁用时,站点则切换到静态版 Doc/improve-page-nojs.rst,该版本只提供不带预填参数的基础链接。维护约束是硬性的:修改其中一份必须同步修改另一份,以保证两类读者体验一致。

二、页面占位符的运行时替换:JavaScript 工作原理

Doc/improve-page.rst 中内嵌了一段 .. raw:: html 区块,仅在 HTML 输出且非 epub 格式时生效。整个替换逻辑围绕两个函数展开:

  1. applyReplacements(text, params):用 URLSearchParams 解析得到的三个查询参数,通过 String.prototype.replacePAGETITLEPAGEURLPAGESOURCE 逐一替换成真实值;
  2. DOMContentLoaded 事件回调:使用 document.createTreeWalker 遍历整棵 DOM 树,对文本节点执行字符串替换,并对链接节点(A 元素)的 href 属性执行同样的替换。

选择 TreeWalker 而不是简单遍历 innerHTML,是为了在保留 DOM 结构的同时精确命中文本节点与链接属性——替换函数对文本与链接都适用,保证了正文描述与超链接目标的一致性。

三、URL 参数从何而来:customsourcelink 模板注入

占位符真正的取值来源是侧边栏模板 Doc/tools/templates/customsourcelink.html。该模板在满足 show_source and has_source and sourcename 条件时渲染"This page"侧边栏区块,包含三条导航:

  • "Report a bug",指向 Doc/bugs.rst 对应的页面;
  • "Improve this page",href 指向 {{ pathto('improve-page-nojs') }}(注意这里链接的是 nojs 版本,再由模板内脚本动态改写成 JS 版本);
  • "Show source",指向该页在 GitHub 上以 ?plain=1 方式展示的原始 .rst 源码。

关键在模板头部的脚本(Doc/tools/templates/customsourcelink.html):

document.addEventListener('DOMContentLoaded', () => {
    const title = document.querySelector('meta[property="og:title"]').content;
    const elements = document.querySelectorAll('.improvepage');
    const pageurl = window.location.href.split('?')[0];
    elements.forEach(element => {
        const url = new URL(element.href.split('?')[0].replace("-nojs", ""));
        url.searchParams.set('pagetitle', title);
        url.searchParams.set('pageurl', pageurl);
        url.searchParams.set('pagesource', "{{ pagename }}.rst");
        element.href = url.toString();
    });
});

这段脚本做了三件事:

  • 从页面 <meta property="og:title"> 中读取当前文档页标题,作为 pagetitle 参数;
  • 取当前浏览器地址(去掉查询串部分)作为 pageurl
  • 用 Sphinx 模板变量 {{ pagename }}(即当前页的源码路径)拼接 .rst,生成 pagesource

同时,它把链接中 -nojs 后缀去掉,等价于把读者引导到 Doc/improve-page.rst 页面——该页面再借助第一节所述的脚本完成最终占位符替换。也就是说,从"点击侧边栏链接"到"生成带上下文的讨论帖/issue"中间经过了模板层注入参数 → 反馈页替换占位符的两级接力。

在 Sphinx 侧,Doc/conf.py 通过 templates_path = ['tools/templates'] 指定自定义模板目录,并用 html_sidebars 为所有页面('**')配置了 ['localtoc.html', 'relations.html', 'customsourcelink.html'] 三段侧边栏,这正是该模板能出现在每一页的配置根源。

四、渠道一:在 Python 讨论论坛发起预填话题

Doc/improve-page.rst 提供了第一种反馈方式:在 Python 官方讨论论坛(Discourse)的 Documentation 分类下开启一个话题。

其链接构造为预填式:点击后会自动携带 category=documentation 分类参数,以及以 Question about page "PAGETITLE" 为标题、以 About the page at PAGEURL: 为正文开头的模板内容。JS 版本由 Doc/improve-page.rst 内联在链接中,静态版则由 Doc/improve-page-nojs.rst 提供不带预填内容的纯分类链接。

适用场景:你并非要报告明确的错误,而是希望就某一页的写法、深度或组织方式展开社区讨论,收集多方意见后再决定是否提交修改。

五、渠道二:通过 GitHub issue 模板提交文档问题

第二种方式更为正式:在 CPython 的 GitHub issue 跟踪器提交一个问题单。Doc/improve-page.rst 给出的链接同样经过预填——它指向 documentation.yml 这一专用 issue 模板,标题预设为 Docs: problem with page "PAGETITLE",描述区预设为 The page at PAGEURL has a problem:,引导提交者把问题精确定位到某个具体页面。

CPython 官方对这类文档问题有明确的汇总实践:Doc/bugs.rst 指出,文档缺陷与改进建议应提交到问题跟踪器;如果你还知道修复思路,应当一并附上。仓库中还维护着一个带 docs 标签的开放问题列表可供检索。

报告前请遵循 Doc/bugs.rst 给出的通用提交流程:

  1. 先用跟踪器的搜索框确认问题是否已被报告,避免重复提交;
  2. 登录 GitHub 账号(匿名无法提交 issue);
  3. 点击 "New issue" 创建问题单,标题保持简短(少于十个词),正文详细描述预期行为与实际行为,并注明涉及的扩展模块、硬件/软件平台与版本信息。

对于 bug 报告的更通用规范,Doc/bugs.rst 还整理了 "Using the Python issue tracker" 一节,介绍了从登录到填表再到等待开发者回复的完整闭环。

六、渠道三:直接编辑页面源码并提交 Pull Request

如果你已经清楚问题出在哪里、甚至知道如何修改,最高效的路径是直接动手:点击页面上的 "Improve this page" 或 "Show source"(两者都指向以 ?plain=1 渲染的 .rst 源码),编辑后即可开启一个 Pull Request 进入贡献流程。正如 Doc/improve-page.rst 所描述的:"edit the page on GitHub to open a pull request and begin the contribution process"。

在动手前,了解文档源码的组织方式很有帮助。CPython 全部文档以 reStructuredText 格式存放在仓库的 Doc 目录中,按主题分子目录:library/(标准库参考)、c-api/(C API)、howto/(指南)、tutorial/(教程)、reference/(语言参考)、faq/whatsnew/(版本新特性)等。每个文档页面对应一个 .rst 文件,例如本文介绍的反馈页面就是 Doc/improve-page.rst

如果你想在自己机器上验证文档改动的渲染效果,仓库在 Doc 目录中提供了完整的 Sphinx 构建配置:

  • Doc/conf.py 定义了主题、扩展、侧边栏布局、translation 标签逻辑等全部构建参数;
  • Doc/Makefile(以及 Windows 下的 Doc/make.bat)提供了本地构建文档的入口。

构建完成后打开本地 HTML 页面,即可预览修改后的排版与链接。注意:本文的 Doc/improve-page.rst 属于"双份维护"页面,若你的修改涉及正文行为,请务必同步修改其无 JS 版本 Doc/improve-page-nojs.rst,保持两个文件内容一致,否则文件头部的维护注释即构成未满足的约束。

七、翻译版本的特殊处理

面向翻译读者的反馈路径与英文版不同。当文档被以翻译模式构建时(构建参数携带 language=...),Doc/conf.py 会做两件事:

  1. translation 标签加入 Sphinx 标签集合,从而启用两个 improve 页面与 Doc/bugs.rst 中所有 .. only:: translation 条件的区块;
  2. rst_epilog 中动态定义 TRANSLATION_REPO 锚点:若指定了语言代码,则指向 python-docs-{语言代码} 对应的翻译仓库;否则回退指向 python 组织主页。

于是 Doc/improve-page.rst 中"若缺陷或改进意见涉及文档翻译,请改为在该翻译仓库中开启 issue 或直接编辑页面"的提示,会在英文构建下自动隐藏、在翻译构建下自动出现——同一份源码在不做手工条件判断的情况下,为两种受众呈现不同的指引。

八、完整流程串联与实操要点

综合以上各节,一次"文档改进"从发现到落地通常遵循如下链路:

  1. 在 docs.python.org 阅读任意页面,点击侧边栏 "Improve this page";
  2. 浏览器端脚本经 Doc/tools/templates/customsourcelink.html 注入当前页的 pagetitlepageurlpagesource 三个参数;
  3. 页面 Doc/improve-page.rst 中的替换脚本把参数写入讨论帖、issue 模板或编辑链接,读者到达时上下文已完整;
  4. 根据诉求选择渠道:讨论类问题去 Documentation 论坛分类,明确的错误去 issue 跟踪器并套用 documentation.yml 模板,有修复方案则直接编辑 .rst 源码提交 Pull Request;
  5. 翻译类问题改走对应语言的翻译仓库,由 Doc/conf.py 的构建逻辑决定链接目标。

实操层面需要记住的几个要点:

  • 报告 issue 前先检索,避免重复;标题精炼、正文给出"预期 vs 实际"并附上平台与版本信息(依据 Doc/bugs.rst);
  • 提交 Pull Request 本质上就是修改 Doc 下的 .rst 源文件,可先用 Doc/Makefile 在本地构建预览;
  • 若你正在阅读本文对应的这个特殊页面本身,修改它的同时必须同步更新 Doc/improve-page-nojs.rst,反之亦然;
  • 所有跳转链接都依赖 Doc/tools/templates/customsourcelink.html 中的 {{ pagename }}.rst 约定,因此新增页面时保持源码路径与构建产物的对应关系是模板正常工作的前提。

通过这套机制,Python 官方文档将"读者反馈"到"文档合入"的距离压缩到了最小:无需先学习完整的贡献流程,只需在阅读到有问题的那一页时点一下链接,剩下的上下文(页面标题、地址、源码文件)都会自动替你填好。这正是 CPython 文档质量能够持续得到社区维护的基础设施之一。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388