literalinclude: 引用文件的一部分

literalinclude 在 MyST 里就是 ```{literalinclude} <path> 代码块, 选项和 reST 版本完全一样。路径相对于当前文档, 以 / 开头则相对于 docs/source。

下面所有例子都引用同目录的 example.py。

用注释标记区间 (推荐)

在 Python 文件里用一对注释标记区间:

# --- begin: make-id
def make_id(n: int = 12) -> str:
    ...
# --- end: make-id

然后用 :start-after: 和 :end-before: 只引用中间的部分, 标记行本身不会出现:

```{literalinclude} example.py
:language: python
:start-after: "# --- begin: make-id"
:end-before: "# --- end: make-id"
```

结果:

def make_id(n: int = 12) -> str:
    alphabet = string.ascii_letters
    return "".join(secrets.choice(alphabet) for _ in range(n))

方法内部的区间, 去掉缩进

区间在方法里面时, 用 :dedent: 去掉多余的缩进, 再加上标题和行号:

```{literalinclude} example.py
:language: python
:start-after: "# --- begin: put-body"
:end-before: "# --- end: put-body"
:dedent:
:caption: Store.put 的方法体
:linenos:
```
Store.put 的方法体
1key = make_id()
2self.data[key] = value
3return key

按函数名或类名引用 (不需要注释)

:pyobject: 按名字找到函数、类或方法, 文件怎么改都不用调整:

```{literalinclude} example.py
:pyobject: Store.put
:emphasize-lines: 4
```
    def put(self, value: str) -> str:
        # --- begin: put-body
        key = make_id()
        self.data[key] = value
        return key

引用仓库里其他位置的文件

路径可以指向 docs/source 之外的地方, 比如直接引用这个仓库的 Python 源码:

```{literalinclude} ../../../../sanhe_me_kb/doc_id.py
:pyobject: new_doc_id
```
def new_doc_id() -> str:
    """
    Generate a new random doc_id: 12 characters from ``[A-Za-z]``.
    """
    return "".join(secrets.choice(DOC_ID_ALPHABET) for _ in range(DOC_ID_LENGTH))

选项速查

选项

作用

:start-after: / :end-before:

从某行之后 / 到某行之前 (不含标记行)

:start-at: / :end-at:

从某行开始 / 到某行结束 (含标记行)

:pyobject:

按 Python 函数 / 类 / 方法名引用

:lines:

按行号引用, 例如 1,3,5-10。文件一改就错位, 不推荐

:dedent:

去掉公共缩进

:emphasize-lines:

高亮某几行 (行号相对于引用出来的片段)

:caption: / :linenos:

标题 / 行号

备注

{literalinclude} 在 PyCharm 和 GitHub 的 Markdown 预览里只会显示成代码块里的原文, 只有 Sphinx 构建后才能看到引用的内容。