跳至内容

使用 Jinja2 自定义 Jupyter 笔记本模板

了解如何使用 Jinja2 为您的 Jupyter 笔记本创建自定义导出模板。
已更新 2026年10月6日  · 10分钟 阅读

使用 AI 探索

ChatGPTClaudePerplexity

在数据科学中,您经常需要将自己的工作整理成报告,展示给决策者或其他非技术人员。将您的 Jupyter 笔记本 转换为稳定的 PDF 或 HTML 文档,更便于没有安装 Python 或 Jupyter 的同事查看。Python 使用名为 nbconvert 的库和名为 Jinja2 的模板语言来转换文档。模板定义了文档在网页或其他输出格式中的呈现方式。了解如何自定义模板,有助于为您的笔记本制作更美观的报告。

Jupyter 笔记本是一种在浏览器中运行 Python 代码的方式。如果您想进一步了解 Python,欢迎查看我们的免费课程 面向数据科学的 Python 入门。

在本教程中,您将学习以下内容:

  • 模板与 Jinja2 模板设计器。
  • 模板渲染与继承。
  • 如何使用 nbconvert 导出您的笔记本。
  • 扩展 Jupyter 默认 HTML 导出模板的语法与结构。
  • 导出到 LaTeX 与 PDF 格式的差异。

什么是模板?

引用 Python 维基:“模板化,特别是网页模板化,是以不同形式呈现数据的一种方式……通常,模板解决方案包含一个文档(模板)和数据。模板通常与最终输出非常相似,只是把实际数据换成了占位符。”

Jupyter 笔记本可以通过 File -> Download As(在 Jupyter Lab 中,您会看到 Export Notebook As)轻松导出。该选项使用存放在主 Jupyter 环境中的默认模板。Jinja2 是一个功能强大的 Python 模板语言,用于定义区块和排版。模板包含由标签定义的各个部分,指示模板如何渲染输入数据。渲染时,数据会替换模板中的变量或表达式。

模板不同部分的定界符为:

  • {% ... %}:语句
  • {{ ... }}:要打印到模板输出的表达式
  • {# ... #}:不会包含在模板输出中的注释

看一个简短的 Jinja 模板示例(摘自 Jinja2 文档):

<!DOCTYPE html>

<html lang="en">

<head>

    {% block head %}
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %} - My Webpage </title>
    {% endblock %}
</head>

<body>

    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
        {% block footer %}
        &copy; Copyright 2008 by <a href="http://domain.invalid">you </a>.
        {% endblock %}
    </div>
</body>

</html>

您可以看到,上面的模板与普通 HTML 文档非常相似。Jinja 只需要少量额外语句即可将代码按模板解释。{% block head %} 定义了 HTML 文档的 head 区域,以及该模板将如何扩展其格式。{% block title %} 指定了输入标题显示的位置。{% endblock %} 多次出现,因为它用于结束相应的模板区块。

现在,您已经可以开始学习如何使用 Jinja 来创建属于自己的自定义模板了!

Jinja 简介

Jinja 是一个模板引擎,允许您定义文档的显示方式。具体来说,在本教程中,您将重点学习如何借助 Jinja 模板导出您的 Jupyter 笔记本。

首先,从 Jinja2 导入 Template:

from jinja2 import Template

理解模板的基础渲染

在 Jinja 模板中渲染数据相当直接。使用花括号和变量名,您就可以在模板中显示数据:

myTemplate = Template("My template is {{ something }}!")
myTemplate.render(something="awesome")
'My template is awesome!'

调用 .render(input) 可以让您在笔记本中显示模板,并用您的输入替换模板中的通用占位 {{ something }}。这是 Jinja 中使用表达式的一个示例。

您还可以通过定义 Python 语句,让模板更具动态性,Jinja 会对其进行解释。

myFancyTemplate = Template("Let's count to 10: {% for i in range(11) %}{{i}} " "{% endfor %}")
myFancyTemplate.render()
"Let's count to 10: 0 1 2 3 4 5 6 7 8 9 10 "

注意,您定义了一个 for 循环,模板按空格分隔渲染了 0 到 10 的数字。{% expression %} 这样的语句语法在制作自定义模板时提供了很大的灵活性。

模板继承

为了扩展 Jupyter 默认的导出模板,您可以使用模板继承。继承是编程中的一个概念,指您可以在子对象中实现某些功能,同时利用父对象已定义的功能。一个简单例子是,如果您有一个可以叫、吃、走的 Dog 对象,您可以使用继承创建一个 Dalmatian(斑点狗)对象,继承这些属性并新增如有斑点等属性。您将在本教程中看到继承在模板中的作用非常大,因为通常只需做一些小改动即可自定义输出。与其他具备继承特性的语言类似,Jinja 使用 extends 与 super 等关键字来访问父级定义。

看看上面名为 base.html 的父模板示例:

<!DOCTYPE html>
<html lang="en">

<head>
    {% block head %}
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %} - My Webpage </title>
    {% endblock %}
</head>

<body>
    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
        {% block footer %}
        &copy; Copyright 2008 by <a href="http://domain.invalid">you </a>.
        {% endblock %}
    </div>
</body>

</html>

一个子模板可能如下所示(摘自 Jinja2 文档):

{% extends "base.html" %}

{% block title %}Index{% endblock %}

{% block head %}
    {{ super() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}

{% block content %}
    <h1>Index</h1>
    <p class="important">
      Welcome to my awesome homepage.
    </p>
{% endblock %}

请注意,子模板以 {% extends "base.html" %} 开头。该声明告诉 Jinja 模板引擎如何处理此文档(作为继承自 base.html 的 HTML)。使用该子模板可以为首页指定不同属性(例如特定的 CSS 颜色)。此外,您可以在head 区块中看到,子模板通过调用 super() 继承了父模板的样式。

使用 nbconvert 导出 Jupyter 笔记本

现在您已经了解了模板的基本语法和继承机制,接下来学习如何使用 nbconvert 导出 Jupyter 笔记本,并通过定义模板自定义输出。

首先导入 nbconvert:

import nbconvert

nbconvert 可以生成多种输出格式。本教程将重点介绍 HTML 和 LaTeX/PDF 输出。要在笔记本中查看输出,请使用 IPython 的 display 函数,并在调用 nbconvert 时添加 --stdout。

example = !jupyter nbconvert --to html 'Example.ipynb' --stdout
from IPython.display import HTML, display
display(HTML('\n'.join(example)))

[NbConvertApp] Converting notebook Example.ipynb to html

converting notebook example

这段笔记本的输出与原始 .ipynb 文件非常相似。输出以独立文档的形式显示,标题和文本的呈现方式与笔记本中通常的显示接近。代码单元格以灰色方框显示(称为“Notebook 风格”)。您能看到的主要差异是,Jupyter 默认的 HTML 模板不会显示类似于活动笔记本中的 “Out:” 提示。

使用 nbconvert 和自定义子模板导出 Jupyter 笔记本

通常,您会希望在 Jupyter 笔记本的默认导出模板之上进行扩展,并对输出做一些小的设计更改。

例如,看看这个从输出中移除 Markdown 单元格的简单模板(名为 rmMkdwn.tpl):

{% extends 'basic.tpl'%}

{% block markdowncell -%}
{% endblock markdowncell %}

将模板应用于 nbconvert 可通过 --template= 选项实现:

example = !jupyter nbconvert --to html 'Example.ipynb' --template='rmMkdwn.tpl' --stdout
display(HTML('\n'.join(example)))

[NbConvertApp] Converting notebook Example.ipynb to html converting notebook example 2 即便是像 rmMkdwn.tpl 这样非常简单的模板,也能极大地帮助您自定义输出。

再看一个更复杂的模板,它为单元格加上红色边框(名为 boxRed.tpl):

{% extends 'full.tpl'%}

{% block any_cell %}
    <div style="border:thin solid red">
        {{ super() }}
    </div>
{% endblock any_cell %}
example = !jupyter nbconvert --to html 'Example.ipynb' --template='boxRed.tpl' --stdout
display(HTML('\n'.join(example)))

[NbConvertApp] Converting notebook Example.ipynb to html converting notebook example 3

如上所示,唯一的样式更改是每个单元格外面的红色边框。使用 super() 可确保每个单元格保留其从父模板 full.tpl 继承的个体样式。

导出到 LaTeX 与 PDF 时模板的差异

由于 { } 和 % 在 LaTeX 中是特殊字符,因此需要改用 (( )) 和 *。此外,默认的 LaTeX 模板为 base.tplx、article.tplx 和 report.tplx,它们分别对应 LaTeX 的文档类。

看看如何通过 LaTeX 子模板移除 Markdown 单元格:

((* extends 'article.tplx' *))

((* block markdowncell -*))
((* endblock markdowncell *))

nbconvert 可以生成 LaTeX 或 PDF 输出——PDF 输出由 LaTeX 模板编译而成。为便于本教程中的查看,看看使用 rmMkdwn.tplx 导出为 PDF 时会发生什么。

!jupyter nbconvert --to pdf 'Example.ipynb' --template='rmMkdwn.tplx'
from IPython.display import IFrame
IFrame('Example.pdf', width=800, height=500)
[NbConvertApp] Converting notebook Example.ipynb to pdf
[NbConvertApp] Support files will be in Example_files/
[NbConvertApp] Making directory Example_files
[NbConvertApp] Writing 16047 bytes to notebook.tex
[NbConvertApp] Building PDF
[NbConvertApp] Running xelatex 3 times: ['xelatex', 'notebook.tex']
[NbConvertApp] Running bibtex 1 time: ['bibtex', 'notebook']
[NbConvertApp] WARNING | bibtex had problems, most likely because there were no citations
[NbConvertApp] PDF successfully created
[NbConvertApp] Writing 16102 bytes to Example.pdf

pdf output

请注意,该输出与 HTML 版本有很大不同。LaTeX 会将第一个 Markdown 单元格作为论文标题处理,因此它仍会显示在输出中。模板确实移除了副标题(因此它把那个 Markdown 单元格视为真正的 Markdown)。文章文档类会更新为今天的日期——这在原始笔记本中并不存在。字体和行距也不同于 HTML 版本。最后,默认情况下输出使用经典的 IPython 显示风格,而不是“Notebook 风格”。

如果您选择扩展 Jupyter 中的某个 LaTeX 文档类,请确保了解它将采用的格式设置。

总结

关于模板、Jinja2 和 nbconvert,有一些关键点需要记住。

模板定义了文档在网页或其他输出格式中的显示方式。Jupyter 笔记本使用 Jinja 模板来呈现不同的导出格式。模板具有继承规则,允许您为相似页面定义父模板和子模板,只做些许格式差异。

Jinja 模板包含 语句、表达式 和(可选的)注释。用 {% statement %} 定义的语句用于定义模板结构。用 {{ expression }} 定义的表达式用您的数据填充模板。而用 {# comment #} 定义的注释不会显示在输出中——它们仅用于模板内部。

nbconvert 是一个 Python 库,可将您的 Jupyter 笔记本转换为其他格式,例如 HTML、LaTeX 和 PDF。nbconvert 使用 Jinja 模板来定义笔记本在这些格式中的显示方式。您可以定义自定义模板,或使用继承扩展 Jupyter 的默认模板。

现在,您已经可以开始制作自己的模板,并导出精美的 Jupyter 笔记本文档了!

参考资料:

Jinja2 文档

Python 模板化文档

nbconvert 文档

主题
数据科学
Python

进一步学习 Python

课程

Python 函数编写

4 小时
115K
学习使用最佳实践编写可维护、可复用、复杂且文档完善的函数。
查看详情Right Arrow
开始课程
查看更多Right Arrow