<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>后端教程 on Veno's Blog</title><link>https://v3n0.com/tags/%E5%90%8E%E7%AB%AF%E6%95%99%E7%A8%8B/</link><description>Recent content in 后端教程 on Veno's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><lastBuildDate>Sun, 10 Aug 2025 00:09:19 +0800</lastBuildDate><atom:link href="https://v3n0.com/tags/%E5%90%8E%E7%AB%AF%E6%95%99%E7%A8%8B/index.xml" rel="self" type="application/rss+xml"/><item><title>1.2 Lab0</title><link>https://v3n0.com/post/backend-tutorial/1.2/</link><pubDate>Sun, 10 Aug 2025 00:09:19 +0800</pubDate><guid>https://v3n0.com/post/backend-tutorial/1.2/</guid><description>&lt;p&gt;:::warning
如果你在本篇遇到任何的网络问题或疑似网络问题，请向学长私聊求助。
:::&lt;/p&gt;
&lt;p&gt;工欲利其事，必先利其器。Lab 0 中我们会进行基础的开发环境搭建，并补全一些你可能不知道的 Python 知识。&lt;/p&gt;
&lt;h2 id="概念普及"&gt;概念普及
&lt;/h2&gt;&lt;p&gt;这一小节给大家普及本篇文档可能你会遇到的陌生词语&lt;/p&gt;
&lt;h3 id="linux-发行版distro"&gt;Linux? 发行版(distro)?
&lt;/h3&gt;&lt;p&gt;Linux 严格意义上指的是 Linus Torvalds 最初编写的那个系统内核（kernel）。一个“能用的操作系统”= 内核 + 一堆用户态工具(命令行工具、包管理器、桌面环境&amp;hellip;) + 配置 + 生态整合。不同的社区或公司，会在同一个 Linux 内核基础上，搭建并打包自己的“发行版”(distribution, 简写 distro)。&lt;/p&gt;
&lt;p&gt;常见发行版：Ubuntu、Debian、Fedora、Arch、openSUSE、CentOS / Rocky / Alma、RHEL 等。它们的差异主要体现在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;包管理器不同（Ubuntu 用 APT，Fedora 用 DNF，Arch 用 pacman）&lt;/li&gt;
&lt;li&gt;默认预装的软件 &amp;amp; 配置不同&lt;/li&gt;
&lt;li&gt;软件版本策略（偏“新”还是偏“稳”）&lt;/li&gt;
&lt;li&gt;社区/企业支持方式（社区滚动更新 vs 企业长期维护 LTS）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你现在在 WSL 装的 Ubuntu，就是“Ubuntu 发行版”。说“我用的是 Linux”通常在实际语境里=“我用的是某个 Linux 发行版”。&lt;/p&gt;
&lt;p&gt;:::tip 什么时候需要关心“发行版差异”？
写/跑代码 -&amp;gt; 几乎不用纠结；部署生产、写系统级脚本、看教程命令对不上时 -&amp;gt; 才需要意识到“也许是发行版不一样”。
:::&lt;/p&gt;
&lt;p&gt;:::warning 小坑
网上复制的命令如果带 &lt;code&gt;yum&lt;/code&gt; / &lt;code&gt;dnf&lt;/code&gt; / &lt;code&gt;pacman&lt;/code&gt; 而你系统里只有 &lt;code&gt;apt&lt;/code&gt;，不要怀疑人生——只是发行版不一样，换成对应包管理器就好。
:::&lt;/p&gt;
&lt;h3 id="shell-终端terminal"&gt;Shell? 终端(Terminal)?
&lt;/h3&gt;&lt;p&gt;Terminal（终端）是一个“窗口/程序”，负责把你敲的字符传给后面真正执行命令的“Shell”，再把结果展示出来。Shell 则是“命令解释器”——接收你输入的文本命令，解析、执行，然后输出结果。&lt;/p&gt;
&lt;p&gt;类比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;终端 = 聊天窗口&lt;/li&gt;
&lt;li&gt;Shell = 正在和你对话、帮你办事的“客服”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常见 Shell：bash、zsh、fish、powershell（不是 Linux 传统 shell 但理念类似）。你在 WSL 里默认启动的一般是 bash；很多开发者会换成更好用（补全更强/主题更丰富）的 zsh + oh-my-zsh。&lt;/p&gt;
&lt;p&gt;如何知道自己当前 shell？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;:::tip
“我打开 VS Code 内置终端”“我在 Windows Terminal 新建了一个标签页”——这些动作都是在启动一个“终端程序实例”；里面跑的那一行提示符（&lt;code&gt;veno@pc:~$&lt;/code&gt;）背后那个解释命令的才是 shell。
:::&lt;/p&gt;
&lt;p&gt;:::warning Ctrl+C
在 shell 中 &lt;code&gt;Ctrl + C&lt;/code&gt; 不是复制，是“向前台进程发送中断信号”（终止当前正在运行的命令）。复制请用 &lt;code&gt;Ctrl + Shift + C&lt;/code&gt;（在大多数终端里）。
:::&lt;/p&gt;
&lt;h3 id="包管理器"&gt;包管理器
&lt;/h3&gt;&lt;p&gt;包管理器（package manager）= “下载/安装/升级/卸载 软件/库 的自动化工具 + 依赖关系解决器”。&lt;/p&gt;
&lt;p&gt;举些例子：&lt;/p&gt;
&lt;p&gt;操作系统层面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ubuntu: apt (&lt;code&gt;sudo apt install xxx&lt;/code&gt;), snap&amp;hellip;&lt;/li&gt;
&lt;li&gt;Fedora: dnf&lt;/li&gt;
&lt;li&gt;Arch: pacman, yay, paru&lt;/li&gt;
&lt;li&gt;。。。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;编程语言生态层面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python: pip / (最推荐的) uv / poetry / pdm&lt;/li&gt;
&lt;li&gt;Node.js: npm / pnpm / yarn&lt;/li&gt;
&lt;li&gt;Rust: cargo&lt;/li&gt;
&lt;li&gt;。。。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为什么需要包管理器？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;自动解决依赖：安装 A 顺便装它需要的 B/C&lt;/li&gt;
&lt;li&gt;版本管理：指定版本/锁定版本避免“昨天能跑今天炸”&lt;/li&gt;
&lt;li&gt;统一卸载：不会在系统角落留下一堆孤儿文件&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="虚拟机和容器"&gt;虚拟机和容器
&lt;/h3&gt;&lt;p&gt;虚拟机（Virtual Machine, VM）= 在你的物理机器（Host）里，用软件模拟出另一套“硬件”并在其上运行一个“客体操作系统”。常见软件：VMware、VirtualBox、Hyper-V、WSL2（底层也用类似虚拟化能力）。&lt;/p&gt;
&lt;p&gt;它解决什么问题？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;隔离：不同项目/系统互不影响&lt;/li&gt;
&lt;li&gt;一致性：开发、测试、线上使用一致环境&lt;/li&gt;
&lt;li&gt;安全：把“可能作死”的尝试关在沙盒里&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你可能还见过一个词叫“容器”，简单来说容器就是比虚拟机更轻量更快的系统级隔离工具，同样后端开发中经常用到。&lt;/p&gt;
&lt;p&gt;“虚拟机”和“容器” 区别（简化理解）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;虚拟机：Guest OS 完整存在 -&amp;gt; 较重 -&amp;gt; 启动慢&lt;/li&gt;
&lt;li&gt;容器：共享宿主机内核，只隔离文件/进程/网络命名空间 -&amp;gt; 轻量 -&amp;gt; 启动快&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WSL2 其实就是：微软做的一层“极轻量虚拟机 + 与 Windows 深度整合的文件/网络桥接”。&lt;/p&gt;
&lt;p&gt;:::tip
“我到底该用 WSL 还是直接装虚拟机？”——写后端/学 Linux → 先用 WSL 足够；需要研究内核、做内核模块、玩系统级实验 → 真 VM, 或者直接装实体机 Linux
:::&lt;/p&gt;
&lt;h3 id="python-虚拟环境"&gt;Python 虚拟环境
&lt;/h3&gt;&lt;p&gt;Python 虚拟环境 (virtual environment, venv) = 给某个项目准备的一份“隔离的 Python 解释器 + 其 site-packages 目录”。这样不同项目的依赖（版本）互不污染。&lt;/p&gt;
&lt;p&gt;为什么必须用？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你 A 项目需要 &lt;code&gt;fastapi==0.115.x&lt;/code&gt;，B 项目还停在 &lt;code&gt;0.110.x&lt;/code&gt;，全局安装会冲突。&lt;/li&gt;
&lt;li&gt;线上部署要复现本地依赖组合，需要可复制、可锁定的环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常见方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标准库 &lt;code&gt;python -m venv venv&lt;/code&gt; + &lt;code&gt;source venv/bin/activate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;uv / poetry / pipenv / pdm：在“虚拟环境 + 依赖锁定 + 脚本运行”上提供更高级封装&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;uv 做了什么？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;自动创建/复用隔离环境&lt;/li&gt;
&lt;li&gt;解析 &lt;code&gt;pyproject.toml&lt;/code&gt; 里声明的依赖&lt;/li&gt;
&lt;li&gt;生成/使用锁文件（&lt;code&gt;uv.lock&lt;/code&gt;）保证团队一致&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;:::tip 判断当前是否已激活虚拟环境
执行 &lt;code&gt;which python&lt;/code&gt; / &lt;code&gt;which pip&lt;/code&gt;，如果路径落在项目缓存/虚拟目录里（而不是 &lt;code&gt;/usr/bin/python3&lt;/code&gt;），就说明你在“虚拟”里。或者看提示符是否多了形如 &lt;code&gt;(venv)&lt;/code&gt; 的前缀（取决于工具）。
:::&lt;/p&gt;
&lt;p&gt;:::warning 常见误区&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;“我已经有 WSL 或虚拟机了，还需要 Python 虚拟环境吗？”——需要。系统级环境隔离 ≠ 语言级依赖隔离。&lt;/li&gt;
&lt;li&gt;“直接全局 pip install 不是更简单吗？”——初期简单，后期灾难：版本冲突、无法复现、卸不干净，可能在项目中引入别人没有的依赖也无法发觉。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="开发环境配置"&gt;开发环境配置
&lt;/h2&gt;&lt;h3 id="windows-配置流程"&gt;Windows 配置流程
&lt;/h3&gt;&lt;h4 id="安装-wsl2"&gt;安装 WSL2
&lt;/h4&gt;&lt;p&gt;WSL2 (Windows Subsystem for Linux 2)，本质上其实是一个运行在 Windows 的轻量级 Linux 虚拟机。&lt;/p&gt;
&lt;p&gt;大多数后端服务最终会部署在 Linux 服务器中，因此对于后端学习，我们最好尽快熟悉 Linux 的命令行操作。&lt;/p&gt;
&lt;p&gt;对于 Windows 10 版本 2004 及更高版本（内部版本 19041 及更高版本）或 Windows 11 ，使用以下教程：&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://learn.microsoft.com/zh-cn/windows/wsl/install" target="_blank" rel="noopener"
&gt;如何使用 WSL 在 Windows 上安装 Linux&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对于 Windows 10 老版本（低于上面所说的版本），参考：&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://learn.microsoft.com/zh-cn/windows/wsl/install-manual" target="_blank" rel="noopener"
&gt;旧版 WSL 的手动安装步骤&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上面的微软式中文文档经过一些零基础小白的测试，已经确定会给他们造成一些歧义，而英文不会。你可以选择切换到英文阅读上面给出的官方文档，或者跟着本流程走一遍。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;下面我们正式开始 WSL2 的安装。&lt;/p&gt;
&lt;p&gt;如果你是 Windows 11, 那么打开你的 Windows 开始菜单，搜索“终端”或“Terminal”或“Windows Terminal”，你应该能搜到这个应用，它是默认附加在 Windows 11 上的。通过这个应用你可以更方便地以标签页的方式开启和管理你的 Shell 窗口，就像浏览器的标签页一样。&lt;/p&gt;
&lt;p&gt;我们使用它打开一个管理员权限的 Powershell, 在其中输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;wsl&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;-install&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果这里你出现了一些奇怪的报错，比如下图:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://v3n0.com/post/backend-tutorial/1.2/1.2-6.png"
width="683"
height="283"
srcset="https://v3n0.com/post/backend-tutorial/1.2/1.2-6_hu_5ad94a0aca141f02.png 480w, https://v3n0.com/post/backend-tutorial/1.2/1.2-6_hu_8431aaad9b360f9a.png 1024w"
loading="lazy"
alt="1.2-6"
class="gallery-image"
data-flex-grow="241"
data-flex-basis="579px"
&gt;&lt;/p&gt;
&lt;p&gt;403 实际上是 HTTP 状态码 403 Forbidden, 这也是网络报错，请向学长私聊求助。&lt;/p&gt;
&lt;p&gt;:::tip&lt;/p&gt;
&lt;p&gt;截至编写本教程时，wsl &amp;ndash;install 会默认安装 Ubuntu 24.04 LTS 版本。本教程假设你安装的是该版本。&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;这个指令会自动帮你启用 Windows 的虚拟机平台功能，并安装 Ubuntu 作为 WSL 的默认发行版。安装完成之后，如果可能的话，则会自动启动 Ubuntu, 开始用户名和密码的初始化。&lt;/p&gt;
&lt;p&gt;但你大概率之前没有启用过虚拟机平台功能，除非你安装过 VMWare 之类的虚拟机软件。这个时候并不会自动启动 Ubuntu。此时界面应当会类似下图：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://v3n0.com/post/backend-tutorial/1.2/1.2-1.png"
width="1734"
height="927"
srcset="https://v3n0.com/post/backend-tutorial/1.2/1.2-1_hu_ffa5555cb61753bd.png 480w, https://v3n0.com/post/backend-tutorial/1.2/1.2-1_hu_bad72c513f6a3ad8.png 1024w"
loading="lazy"
alt="1.2-1"
class="gallery-image"
data-flex-grow="187"
data-flex-basis="448px"
&gt;&lt;/p&gt;
&lt;p&gt;此时虚拟机平台功能和 Ubuntu 都已经成功安装，只是因为虚拟机平台功能需要重启电脑才能启用，因此才没有自动启动 Ubuntu 。&lt;/p&gt;
&lt;p&gt;我们需要重启电脑，再次打开 Windows Terminal, 在 Powershell 中输入:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如此即可启动 Ubuntu。你也可以在 Windows Terminal 中将 Ubuntu 添加到下拉菜单快捷启动列表里，以后启动会更方便。&lt;/p&gt;
&lt;p&gt;系统将要求你为 Linux 发行版创建“用户名”和“密码”。用户名建议使用3-8个英文小写字符。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;此用户名和密码特定于安装的每个单独的 Linux 分发版，与 Windows 用户名无关。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;注意，输入密码时，屏幕上不会显示任何内容。这称为盲人键入。你不会看到你正在键入的内容，这是完全正常的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建用户名和密码后，该帐户将是分发版的默认用户，并将在启动时自动登录。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;此帐户将被视为 Linux 管理员，能够运行 &lt;code&gt;sudo&lt;/code&gt; (Super User Do) 管理命令。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 WSL 上运行的每个 Linux 发行版都有其自己的 Linux 用户帐户和密码。 每当添加分发版、重新安装或重置时，都必须配置一个 Linux 用户帐户。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;设置用户名和密码之后，我们正式完成了 WSL 的安装。&lt;/p&gt;
&lt;p&gt;注意区分，本文以后的所有命令行操作如果未说明，则默认是在 Ubuntu 的 Shell 环境中运行，而不是 Powershell。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="设置镜像源"&gt;设置镜像源
&lt;/h4&gt;&lt;p&gt;由于网络原因，我们需要给 Ubuntu 设置软件仓库的镜像源，才能正常安装软件包。&lt;/p&gt;
&lt;p&gt;:::tip
&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E7%BD%91%E7%AB%99%E9%95%9C%E5%83%8F" target="_blank" rel="noopener"
&gt;网站镜像&lt;/a&gt;（mirror sites, mirrors；镜像站点，镜像网站）是指对网站内容的拷贝，这类网站通常具有与原站不同的URL，但托管了相同或者是几乎相同的内容。镜像原意是光学里指的物体在镜面中所成之像。引申到计算机网络上，镜像通常用于为相同信息内容提供不同的源，特别是在下载量大的时候提供了一种可靠的网络连接。
:::&lt;/p&gt;
&lt;p&gt;这里我们使用清华大学镜像站。在搜索引擎搜索&lt;code&gt;ubuntu 清华镜像&lt;/code&gt;，你应该可以搜到下面的网站。&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/" target="_blank" rel="noopener"
&gt;ubuntu | 镜像站使用帮助 | 清华大学开源软件镜像站&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们使用的是 24.04 LTS。想确认你的 wsl 安装了什么版本的 ubuntu，你可以运行:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsb_release -a
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;镜像站使用帮助中有这样的描述：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在 Ubuntu 24.04 之前，Ubuntu 的软件源配置文件使用传统的 One-Line-Style，路径为 &lt;code&gt;/etc/apt/sources.list&lt;/code&gt;；从 Ubuntu 24.04 开始，Ubuntu 的软件源配置文件变更为 DEB822 格式，路径为 &lt;code&gt;/etc/apt/sources.list.d/ubuntu.sources&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;将系统自带的对应文件做个备份，然后根据格式的选择下面对应的内容替换，即可使用选择的软件源镜像。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;要备份，其实就是复制一份原文件出来的意思。Linux 中的复制指令是&lt;code&gt;cp&lt;/code&gt;, 即 copy 的缩写。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 这里相当于复制了一份文件到ubuntu.sources.bak, 之后可以放心修改 ubuntu.sources 了。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;之后，选择 DEB882 格式的正确 Ubuntu 版本，复制它生成的配置，替换原来的镜像源文件内容。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nano /etc/apt/sources.list.d/ubuntu.sources
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;输入指令，你会看到类似这样的界面(文件名没有 &lt;code&gt;.bak&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://v3n0.com/post/backend-tutorial/1.2/1.2-2.png"
width="1280"
height="667"
srcset="https://v3n0.com/post/backend-tutorial/1.2/1.2-2_hu_821525cc0d704d72.png 480w, https://v3n0.com/post/backend-tutorial/1.2/1.2-2_hu_f2a3244e29fdc0ea.png 1024w"
loading="lazy"
alt="wsl2-2"
class="gallery-image"
data-flex-grow="191"
data-flex-basis="460px"
&gt;&lt;/p&gt;
&lt;p&gt;:::tip
nano 是 Unix 和类 Unix 系统中的一个终端文本编辑器。它通过 Control 键来控制。比如 Ctrl+O 保存当前文件；Ctrl+W 进入搜索菜单。nano 在屏幕底部显示两行快捷键，列出了当前状态下能用的命令。如果要查看完整的列表，可以按 Ctrl+G 进入帮助屏幕。nano同时支持用鼠标点击屏幕下方的快捷键来操作。
:::&lt;/p&gt;
&lt;p&gt;下面快捷键提示中的&lt;code&gt;^&lt;/code&gt;指的是 Ctrl，&lt;code&gt;M&lt;/code&gt; 是“Meta 键”的缩写，在这里实际上是指 Alt 键。&lt;/p&gt;
&lt;p&gt;我们需要删除文件原来的内容，把我们刚刚从网站上复制的配置复制进去。按住 &lt;code&gt;Shift + 方向键下&lt;/code&gt;, 控制光标选中文件全部内容，之后&lt;code&gt;^K Cut&lt;/code&gt;剪切掉。&lt;/p&gt;
&lt;p&gt;这里之所以是剪切而不是退格，是因为 nano 中 Backspace 只会删除掉光标之前的一个字符，而不是删除我们选中的内容。删除掉文件原来的内容之后，我们向文件中用&lt;code&gt;Ctrl + Shift + V&lt;/code&gt;粘贴我们刚刚从镜像站复制的配置。&lt;/p&gt;
&lt;p&gt;:::warning 注意
这里 nano 使用的粘贴板是独立的，并不是 Windows 的粘贴板，也就是我们不应该使用&lt;code&gt;^U&lt;/code&gt;快捷键粘贴我们复制的配置，我们实际上是通过 Windows Terminal ，将 Windows 的粘贴板内容粘贴到 shell 中。你实际上应该使用的“粘贴”快捷键是 &lt;code&gt;Ctrl + Shift + V&lt;/code&gt;。同样，要复制内容我们也是加上 Shift，即 &lt;code&gt;Ctrl + Shift + C&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在 shell 中，&lt;code&gt;Ctrl + C&lt;/code&gt; 一般是终止进程的快捷键。
:::&lt;/p&gt;
&lt;p&gt;正确粘贴之后，内容应该像这样：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://v3n0.com/post/backend-tutorial/1.2/1.2-3.png"
width="1280"
height="667"
srcset="https://v3n0.com/post/backend-tutorial/1.2/1.2-3_hu_77c88b06aa2ffe1f.png 480w, https://v3n0.com/post/backend-tutorial/1.2/1.2-3_hu_5b0394f4c652167f.png 1024w"
loading="lazy"
alt="1.2-3"
class="gallery-image"
data-flex-grow="191"
data-flex-basis="460px"
&gt;&lt;/p&gt;
&lt;p&gt;接下来保存文件。&lt;code&gt;^O&lt;/code&gt;保存文件，会询问保存的文件名，直接回车保持文件名原样即可。之后&lt;code&gt;^X&lt;/code&gt;退出 nano。&lt;/p&gt;
&lt;p&gt;修改完镜像源之后，我们更新软件仓库，保证同步:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo apt upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;:::tip
有没有觉得这些配置编辑操作相当麻烦？你可以尝试学习使用 vim 编辑器，当你熟练使用之后，我们在终端编辑这种配置文件会比 nano 便捷的多。未来的开发中，我们将不可避免地经常在终端中编辑配置文件。
:::&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="python-环境配置"&gt;Python 环境配置
&lt;/h4&gt;&lt;p&gt;本教程基于 Python 3.12 或更高版本。截止教程编写时，wsl 默认安装 Ubuntu 24.04 LTS ，该版本已经默认安装了 Python 3.12.3。&lt;/p&gt;
&lt;p&gt;在 ubuntu 中查看当前的 Python 版本:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 --version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;你可能听说过 pip, 它是 Python 基础的包管理器。但现代 Python 开发中我们一般使用更为便捷的包和项目管理器，例如 uv, poetry, pdm 等。本教程使用 &lt;a class="link" href="https://docs.astral.sh/uv/" target="_blank" rel="noopener"
&gt;uv&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;uv 是一个比较新的工具，Ubuntu 软件源不一定包含。我们使用官方的安装脚本:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -LsSf https://astral.sh/uv/install.sh &lt;span class="p"&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果安装正确，输出应类似下图:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://v3n0.com/post/backend-tutorial/1.2/1.2-5.png"
width="1235"
height="342"
srcset="https://v3n0.com/post/backend-tutorial/1.2/1.2-5_hu_b710d53900121ef6.png 480w, https://v3n0.com/post/backend-tutorial/1.2/1.2-5_hu_21fc5afcfcdd96d0.png 1024w"
loading="lazy"
alt="1.2-5"
class="gallery-image"
data-flex-grow="361"
data-flex-basis="866px"
&gt;&lt;/p&gt;
&lt;p&gt;这个输出告诉我们，要使用 uv, 我们需要重启一个 Shell。我们新开一个 Ubuntu 窗口即可。&lt;/p&gt;
&lt;p&gt;uv 是一个很强大的工具，建议阅读它的文档，学习使用。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="vs-code-配置"&gt;VS Code 配置
&lt;/h4&gt;&lt;p&gt;本教程使用 VS Code 作为我们的 IDE。&lt;/p&gt;
&lt;p&gt;省流：&lt;strong&gt;VS Code + WSL 插件 + Python 相关插件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;安装 VS Code。&lt;a class="link" href="https://code.visualstudio.com/download" target="_blank" rel="noopener"
&gt;下载链接&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;安装并打开之后，在左侧的插件栏搜索简体中文插件以及 WSL 插件，安装。之后我们就可以在 ubuntu 中使用&lt;code&gt;code&lt;/code&gt;指令打开 Windows 中的 VS Code 了。&lt;/p&gt;
&lt;p&gt;我们首先使用 uv 创建我们的第一个 Python 项目:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; ~ &lt;span class="c1"&gt;# 移动到家目录(/home/veno)。家目录通常被 &amp;#34;~&amp;#34; 指代&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;pwd&lt;/span&gt; &lt;span class="c1"&gt;# 显示当前工作目录 (present working diretory)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/home/veno/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mkdir -p Projects/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; Projects/ &lt;span class="c1"&gt;# 创建 Projects/ 文件夹并进入&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ uv init backend_tutorial &lt;span class="c1"&gt;# 初始化我们的第一个 Python 项目&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Initialized project &lt;span class="sb"&gt;`&lt;/span&gt;backend-tutorial&lt;span class="sb"&gt;`&lt;/span&gt; at &lt;span class="sb"&gt;`&lt;/span&gt;/home/veno/Projects/backend_tutorial&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ code backend_tutorial &lt;span class="c1"&gt;# 在 backend_tutorial 文件夹打开 VSCode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;:::tip&lt;/p&gt;
&lt;p&gt;在文档中，对于多条指令，&lt;code&gt;$&lt;/code&gt;字符一般是为了标识一条指令的开头。偷懒复制粘贴的时候可别把&lt;code&gt;$&lt;/code&gt;也一起复制进去了。&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;此时 Ubuntu WSL 应该会自动开始安装 VSCode 服务器，并打开一个 VS Code 窗口:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://v3n0.com/post/backend-tutorial/1.2/1.2-4.png"
width="2560"
height="1380"
srcset="https://v3n0.com/post/backend-tutorial/1.2/1.2-4_hu_50d0db01c12de7f7.png 480w, https://v3n0.com/post/backend-tutorial/1.2/1.2-4_hu_21350c0f8e8ea0a2.png 1024w"
loading="lazy"
alt="1.2-4"
class="gallery-image"
data-flex-grow="185"
data-flex-basis="445px"
&gt;&lt;/p&gt;
&lt;p&gt;uv 很方便吧？一下就帮我们把项目初始化好了。&lt;/p&gt;
&lt;p&gt;之后，我们在 Ubuntu 的 VS Code 中安装我们所需的所有插件。注意你需要把插件安装到 “WSL:UBUNTU”，而不是“本地”。&lt;/p&gt;
&lt;p&gt;你至少需要安装：Python, Pylance, Git Graph。你可以自己探索其他好用的插件。&lt;/p&gt;
&lt;p&gt;本 wiki 的 &lt;a class="link" href="https://hdu-cs.wiki/s/20034016" target="_blank" rel="noopener"
&gt;C-Start&lt;/a&gt; 课程提供的 VS Code 的配置文件中有一套开箱即用的 C/C++ 配置。你可以参考这个配置文件中好用的插件。大多数时候，等到需要写什么格式的文件再装什么插件就行。&lt;/p&gt;
&lt;h4 id="git-配置"&gt;Git 配置
&lt;/h4&gt;&lt;p&gt;Git 用于我们项目的版本控制。现在不熟悉没关系，你暂时只需要记住一些基础操作就行。&lt;/p&gt;
&lt;p&gt;首先我们在 Ubuntu 安装 git:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;安装之后，需要先进行一些配置工作。输入以下指令:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global user.name &lt;span class="s2"&gt;&amp;#34;Zhang San&amp;#34;&lt;/span&gt; &lt;span class="c1"&gt;# your name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global user.email &lt;span class="s2"&gt;&amp;#34;zhangsan@foo.com&amp;#34;&lt;/span&gt; &lt;span class="c1"&gt;# your email&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;放心，这里的 name 和 email 只是一个标识符，不会真有人给你发验证邮件什么的，填的邮箱不存在也无所谓。在你每次提交代码的时候你都得靠这个标签来说明这个版本是谁提交的。要不然 git 会不让你提交代码。&lt;/p&gt;
&lt;p&gt;想学习 Git 的基本操作，你可以看看&lt;a class="link" href="https://learngitbranching.js.org/?locale=zh_CN" target="_blank" rel="noopener"
&gt;Learn Git Branching&lt;/a&gt;, 闯关式，交互式的 git 教程，很有意思。&lt;/p&gt;
&lt;p&gt;关于 Git 和 Github 的更多内容你可以参考&lt;a class="link" href="https://hdu-cs.wiki/s/23868938" target="_blank" rel="noopener"
&gt;旧版 Wiki&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="linux-配置流程"&gt;Linux 配置流程
&lt;/h3&gt;&lt;p&gt;你都装上 Linux 了，该自己动手丰衣足食了(&lt;/p&gt;
&lt;h3 id="macos-配置流程"&gt;MacOS 配置流程
&lt;/h3&gt;&lt;p&gt;我没有 Macbook，等一个有 Macbook 的好心人提一个 PR。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="python-开发知识普及"&gt;Python 开发知识普及
&lt;/h2&gt;&lt;p&gt;根据本教程的前置知识要求，你至少已经学会了一门编程语言的基本语法了，或许学的就是 Python。为了以后少走一点弯路，我们在 Lab 0 补齐一些现代 Python 开发的知识。&lt;/p&gt;
&lt;h3 id="type-hint类型提示"&gt;Type Hint(类型提示)
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Python 是一门强类型，动态类型的语言！&lt;/strong&gt; 虽然 Python 作为解释型语言看起来语法很随意，类型很随意，但它实际上是有严格的类型验证的，只不过和编译语言不同，Python 作为解释型动态类型语言，对类型的检查被放在了运行时。关于这一点。你可以阅读 Stack Overflow - &lt;a class="link" href="https://stackoverflow.com/questions/11328920/is-python-strongly-typed" target="_blank" rel="noopener"
&gt;Is Python Strongly Typed?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在后端世界，代码不再是几十行的小脚本了，而是成百上千行，多人协作，需要长期维护的复杂系统。类型注解是一个必须项。&lt;/p&gt;
&lt;p&gt;确保你阅读&lt;a class="link" href="https://fastapi.tiangolo.com/zh/python-types/" target="_blank" rel="noopener"
&gt;FastAPI 文档 - Python 类型提示简介&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;通过写类型注解，你可以明确声明各种变量的类型，并让你的 IDE 在编写代码时就帮你检查类型。写代码时候的这点多敲的字永远好过代码上线之后，周末凌晨被叫起来修 bug 的痛苦。并且有类型注解之后，才能利用好 IDE 的自动补全功能，这会极大提高你的开发效率。&lt;/p&gt;
&lt;p&gt;基本上除了 Python, 大多数语言都需要你写出明确的类型声明。趁早适应这一点，别被 Python 惯坏了。&lt;/p&gt;
&lt;h3 id="现代类型标注写法"&gt;现代类型标注写法
&lt;/h3&gt;&lt;p&gt;教程使用 Python 3.12。我们不是开发一个开源库，也不是维护什么企业历史遗留项目，不需要考虑兼容问题。因此本教程将全面使用现代类型标注写法。&lt;/p&gt;
&lt;p&gt;现代写法更加简洁易读，性能更优，并且与现代 Python 后端框架的集成度更好。&lt;/p&gt;
&lt;p&gt;上面的 FastAPI 文档中的大多数写法都是兼容到 Python 3.8+。这里我大概列举一下现代写法和旧写法的参照，建议遵循现代写法来写 Python 代码。&lt;/p&gt;
&lt;h4 id="联合类型union-types"&gt;联合类型(Union Types)
&lt;/h4&gt;&lt;p&gt;现代(3.10+): 使用&lt;code&gt;|&lt;/code&gt;操作符&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Optional[str] 的现代写法是 str | None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;旧写法:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_by_id_old&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_name_old&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="标准集合类型"&gt;标准集合类型
&lt;/h4&gt;&lt;p&gt;现代(3.9+): 直接使用内置集合类型, 如&lt;code&gt;list&lt;/code&gt;, &lt;code&gt;dict&lt;/code&gt;, &lt;code&gt;tuple&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_coordinates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 嵌套集合类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_groups&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;旧写法:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_data_old&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_coordinates_old&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_groups_old&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="类型别名"&gt;类型别名
&lt;/h4&gt;&lt;p&gt;现代(3.12+): 使用&lt;code&gt;type&lt;/code&gt;语句定义类型别名&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UserData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserData&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_all_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;旧写法:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UserData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UserList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UserData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 或者更老的写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UserData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UserList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UserData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="泛型"&gt;泛型
&lt;/h4&gt;&lt;p&gt;现代(3.12+): 使用类型参数语法&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 泛型函数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 直接在函数名后用方括号定义类型变量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 可以对类型变量进行约束&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# 约束 N 必须是 Number 的子类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 泛型类&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 新写法：直接在类名后用方括号定义类型变量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 使用泛型类&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;int_box&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;str_box&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 泛型类型别名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 新写法：在别名定义中使用方括号&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ListOrNone&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ListOrNone&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;旧写法:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. 必须先定义 TypeVar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;T&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Number&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bound&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# 约束的旧写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. 泛型函数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_first_old&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 3. 泛型类，需要继承 Generic[T]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BoxOld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="返回自身实例"&gt;返回自身实例
&lt;/h4&gt;&lt;p&gt;现代(3.11+): 使用&lt;code&gt;Self&lt;/code&gt;类型&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_admin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;旧写法处理实例创建的时候会有问题:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bound&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ShapeOld&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShapeOld&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;这个方法签名看起来没问题，可以正确地在子类中返回子类类型。&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 我们希望克隆一个与 self 类型完全相同的对象 (T)。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 但是，我们只能调用已知的基类构造器 `ShapeOld()`。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 如果 self 是一个 CircleOld 实例，调用 ShapeOld() 返回的却是一个 ShapeOld 实例。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 这与签名的 -&amp;gt; S 承诺相违背，所以静态类型检查器会报错，我们被迫要type: ignore。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 因此 子类必须重写 clone 方法来返回正确的类型，会导致不可避免的代码重复。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ShapeOld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Type &amp;#34;ShapeOld&amp;#34; is not assignable to return type &amp;#34;S@clone&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CircleOld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ShapeOld&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_radius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;这是一个子类特有的方法。&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="c1"&gt;# Cannot assign to attribute &amp;#34;radius&amp;#34; for class &amp;#34;ShapeOld*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# def clone(self: S) -&amp;gt; S:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 重写 clone 方法以返回正确的 CircleOld 类型。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 这会导致代码重复，因为我们需要手动调用基类构造器。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# return CircleOld(self.scale, self.radius)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;c_old&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CircleOld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;c_old&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_radius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;c_old 修改后半径: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c_old&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 输出: 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cloned_old&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c_old&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;克隆出的对象类型: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloned_old&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 输出: &amp;lt;class &amp;#39;__main__.ShapeOld&amp;#39;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cloned_old&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_radius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# AttributeError: &amp;#39;ShapeOld&amp;#39; object has no attribute &amp;#39;set_radius&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="类型注解annotated-pattern"&gt;类型注解(Annotated Pattern)
&lt;/h4&gt;&lt;p&gt;现代(3.9+): 用于给类型附加额外的元数据，主要被 FastAPI、Pydantic、Typer 等现代框架使用，用于实现依赖注入、数据校验等功能。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringConstraints&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Pydantic 数据校验&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringConstraints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;^[\w\.-]+@[\w\.-]+\.\w+$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# FastAPI 依赖注入&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 数据库连接逻辑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;旧写法:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 没有 Annotated 时，只能在函数体或类定义中通过其他方式实现校验和依赖注入&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;^[\w\.-]+@[\w\.-]+\.\w+$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# FastAPI 早期写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="type-checking"&gt;Type Checking
&lt;/h3&gt;&lt;p&gt;在 VS Code 中 &lt;code&gt;Ctrl + ,&lt;/code&gt; 快捷键打开设置，或是从左下角打开设置，搜索 &lt;code&gt;Pylance type checking mode&lt;/code&gt;, 有这样的设置：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://v3n0.com/post/backend-tutorial/1.2/1.2-7.png"
width="657"
height="609"
srcset="https://v3n0.com/post/backend-tutorial/1.2/1.2-7_hu_2ccf33054325762d.png 480w, https://v3n0.com/post/backend-tutorial/1.2/1.2-7_hu_b4995b74a552e915.png 1024w"
loading="lazy"
alt="1.2-7"
class="gallery-image"
data-flex-grow="107"
data-flex-basis="258px"
&gt;&lt;/p&gt;
&lt;p&gt;开启之后，Pylance 插件会自动检查你的类型问题，在你运行代码前就帮你指出。&lt;/p&gt;
&lt;p&gt;随便写点小脚本的时候至少开 standard 或者 basic, 但任何严肃项目都肯定是要开 strict 的。&lt;/p&gt;
&lt;p&gt;我的个人习惯是，不管什么时候都开着 strict, 养成良好的代码习惯。&lt;/p&gt;</description></item><item><title>1.1 入门篇教学大纲</title><link>https://v3n0.com/post/backend-tutorial/1.1/</link><pubDate>Sat, 09 Aug 2025 23:56:22 +0800</pubDate><guid>https://v3n0.com/post/backend-tutorial/1.1/</guid><description>&lt;p&gt;:::warning 📌
施工中
:::&lt;/p&gt;
&lt;h2 id="before-beginning"&gt;Before Beginning
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;前置知识需求: CS61A, 或掌握至少一门编程语言（如Python）的扎实基础，理解函数、类、简单数据结构（列表、字典、集合等）、递归等核心编程概念, 畅通的网络环境, 了解Python的基础写法, 基本的英语阅读能力, 提问的艺术, 基础CLI操作&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="第一部分-后端基础-python--fastapi--sqlmodel"&gt;第一部分： 后端基础 (Python + FastAPI + SQLModel)
&lt;/h2&gt;&lt;h3 id="教学目标一"&gt;教学目标(一)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;快速上手: 让学生在几小时内，从零开始搭建起一个功能完整的 CRUD (增删改查) API。&lt;/li&gt;
&lt;li&gt;建立自信: 通过 FastAPI 强大的自动文档和 SQLModel 的易用性，让学生感受到现代工具带来的便捷，消除对后端的畏难心理。&lt;/li&gt;
&lt;li&gt;文档阅读: FastAPI 有着非常用户友好的文档, 利用它来培养阅读文档的习惯. 这也是本教程选择SQLModel而不是SQLAlchemy的原因之一&lt;/li&gt;
&lt;li&gt;正确使用AI: 不要让Copilot变成Copybot&lt;/li&gt;
&lt;li&gt;整个教程的每个模块会维护和精进同一个项目(不与 Project 1 相同, 教程项目更倾向于教学示范)&lt;/li&gt;
&lt;li&gt;理解或掌握以下知识：&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;路由函数 (Routing) 与 HTTP 方法 (GET, POST, PUT, DELETE)。&lt;/li&gt;
&lt;li&gt;SQL, ORM 与数据库操作 (CRUD)。&lt;/li&gt;
&lt;li&gt;API-服务-数据 的基本三层架构模式。&lt;/li&gt;
&lt;li&gt;中间件 (Middleware) 的作用。&lt;/li&gt;
&lt;li&gt;基本的安全思想.&lt;/li&gt;
&lt;li&gt;基本的单元测试和集成测试概念和写法&lt;/li&gt;
&lt;li&gt;配置管理: 学会分离开发, 测试, 生产环境&lt;/li&gt;
&lt;li&gt;学会现代部署: 掌握使用 Docker 和 Docker Compose 对应用进行容器化部署的基本技能。&lt;/li&gt;
&lt;li&gt;学会阅读框架文档&lt;/li&gt;
&lt;li&gt;基本的 Git 团队协作能力&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="课程大纲一"&gt;课程大纲(一)
&lt;/h3&gt;&lt;h4 id="lab-0"&gt;Lab 0
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;前后端的基本概念, 后端是什么&lt;/li&gt;
&lt;li&gt;VSCode 配置, &lt;a class="link" href="https://fastapi.tiangolo.com/zh/python-types/" target="_blank" rel="noopener"
&gt;环境变量, Python 虚拟环境, PEP规范和类型标注&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;uv Python 环境管理&lt;/li&gt;
&lt;li&gt;Git基本配置, Github&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块一-api-和-http"&gt;模块一: API 和 HTTP
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;API 和 路由函数&lt;/li&gt;
&lt;li&gt;路径参数和查询参数&lt;/li&gt;
&lt;li&gt;HTTP, GET 和 POST 方法&lt;/li&gt;
&lt;li&gt;请求体和数据校验(pydantic)&lt;/li&gt;
&lt;li&gt;API 文档 (展示FastAPI的自动生成的 Swagger 文档)&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;阅读文档, 找到如何使用 FastAPI 构造一个上传文件的接口.&lt;/li&gt;
&lt;li&gt;通过阅读文档, 发现并解决 FastAPI 中路由函数先后定义产生的问题.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;HTTP MDN, 图解HTTP&lt;/li&gt;
&lt;li&gt;RESTful API 和 WebSocket&lt;/li&gt;
&lt;li&gt;API测试工具&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块二-数据库"&gt;模块二： 数据库
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;SQL语句: 手动使用SQL来进行基础的查询和数据库操作&lt;/li&gt;
&lt;li&gt;ORM 与模型: ORM概念, 使用 SQLModel，定义第一个数据模型。&lt;/li&gt;
&lt;li&gt;连接数据库: 使用 SQLite 作为入门数据库，配置数据库连接。&lt;/li&gt;
&lt;li&gt;实现 CRUD: 编写完整的增、删、改、查四个 API 接口。&lt;/li&gt;
&lt;li&gt;数据库事务的概念和重要性(ACID), SQLModel 的 session&lt;/li&gt;
&lt;li&gt;索引设计&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;提供一个复杂的数据库 ER 图, 要求编写几个不同复杂度的 SQL 查询语句, 覆盖连接 (JOIN), 分组 (GROUP BY), 子查询等。&lt;/li&gt;
&lt;li&gt;用ORM的关系预加载优化一个 N+1 查询问题.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;SQL, NoSQL(MongoDB, Redis, Neo4j)&lt;/li&gt;
&lt;li&gt;索引, 外键, 多对多&amp;hellip;&lt;/li&gt;
&lt;li&gt;alembic 等数据库同步工具&lt;/li&gt;
&lt;li&gt;ACID、CAP 和 BASE&lt;/li&gt;
&lt;li&gt;软删除&lt;/li&gt;
&lt;li&gt;SQL 注入&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块三-代码的规范化"&gt;模块三： 代码的规范化
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;问题引入&lt;/strong&gt;: 当业务逻辑变复杂时，所有代码都写在路由函数里的坏处。&lt;/li&gt;
&lt;li&gt;重构代码: 引入三层架构思想, 把先前的代码清晰分为API层, 服务层, 路由层.&lt;/li&gt;
&lt;li&gt;如何避免过度设计&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;IoC 和 依赖注入&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://refactoringguru.cn/design-patterns/catalog" target="_blank" rel="noopener"
&gt;22种设计模式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SOLID 原则&lt;/li&gt;
&lt;li&gt;领域驱动设计&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块四-中间件"&gt;模块四： 中间件
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;中间件基本概念&lt;/li&gt;
&lt;li&gt;中间件一般应用场景&lt;/li&gt;
&lt;li&gt;错误处理中间件(统一错误响应格式)&lt;/li&gt;
&lt;li&gt;CORS中间件&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;编写一个简单的记录API日志的中间件, 统计请求处理时长.&lt;/li&gt;
&lt;li&gt;实现自定义异常处理中间件&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块五-基本的安全思想"&gt;模块五: 基本的安全思想
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;JWT Token&lt;/li&gt;
&lt;li&gt;passwd_hashed&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;环境变量管理敏感信息&lt;/li&gt;
&lt;li&gt;永远不要相信用户的输入&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;实现一个完整的注册登陆流程, 密码哈希存储&lt;/li&gt;
&lt;li&gt;利用中间件实现API的Token鉴权&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块六交付你的第一个后端服务-容器化"&gt;模块六：交付你的第一个后端服务 (容器化)
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;Docker 入门: 讲解什么是 Docker, 它解决了什么问题.&lt;/li&gt;
&lt;li&gt;Dockerfile: 为 FastAPI 应用编写一个 Dockerfile&lt;/li&gt;
&lt;li&gt;Docker Compose&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;除了Docker以外的容器, Podman, container.d&lt;/li&gt;
&lt;li&gt;CI/CD, Github Actions&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="project-1-电子书商城"&gt;Project 1: 电子书商城
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;与前端组协调, 后端小组与前端小组共同完成电子书商城项目.&lt;/li&gt;
&lt;li&gt;要求:
&lt;ul&gt;
&lt;li&gt;强制使用 Feature Branch 工作流&lt;/li&gt;
&lt;li&gt;编写有意义的 Commit Message&lt;/li&gt;
&lt;li&gt;团队成员之间需要进行 Code Review&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>1.0 后端教程入门篇前言</title><link>https://v3n0.com/post/backend-tutorial/1.0/</link><pubDate>Sat, 09 Aug 2025 19:56:20 +0800</pubDate><guid>https://v3n0.com/post/backend-tutorial/1.0/</guid><description>&lt;p&gt;:::warning 📌
施工中
:::&lt;/p&gt;
&lt;p&gt;欢迎阅读。我是本教程编者&lt;a class="link" href="https://v3n0.com/" target="_blank" rel="noopener"
&gt;V3n0&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="教程的初衷"&gt;教程的初衷
&lt;/h2&gt;&lt;p&gt;我不想让这个教程变成某某语言，某某框架的速通指南。这个教程的目的不是给你一堆可以直接复制的代码，而是带你走过从不会到能独立解决问题的完整路径。&lt;/p&gt;
&lt;p&gt;对于现实场景的后端开发，真正重要的不是死记某个框架的 API，而是通用的后端思维与解决问题的能力: 后端开发通用的核心概念，从业务需求入手的设计思路，如何通过查阅文档来上手一个从来没有用过的框架/语言，如何组织代码结构，如何 debug&amp;hellip;&lt;/p&gt;
&lt;p&gt;我不希望读者在跟完一个教程后，脱离示例代码就无从下手。相反，我希望你能在面对陌生问题时，凭借后端开发的共通思路，结合搜索引擎和文档，独立构建出可运行、可维护的功能。&lt;/p&gt;
&lt;p&gt;有人会问，后端教程非常非常多，为什么我不直接在这里推荐教程呢？&lt;/p&gt;
&lt;p&gt;对于很多后端新手，我主要担心的问题有几点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;过度依赖某一语言/框架，离开它就举步维艰。&lt;/li&gt;
&lt;li&gt;过度依赖教程，陷入教程的死循环。&lt;/li&gt;
&lt;li&gt;缺少“学习方法”的传授，只教结果，不教过程。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我希望补足的就是这些点。对于一些概念性问题，我会尽可能用通俗的方法讲懂。但是对于一切具体的代码示例，我会完整演示如何查阅文档、定位关键 API、逐步推导到可运行代码，而不是直接贴出最终答案。我会假设自己从未使用过教程中提到的框架或库，这样的演示更接近真实开发中遇到的场景。现实里，你很少会记住所有 API，但快速阅读和理解文档的能力是长期有效的核心竞争力。&lt;/p&gt;
&lt;p&gt;本教程不会把每一个概念都讲的非常深入刁钻。对于一些进阶的知识，我会以拓展阅读的形式呈现。&lt;/p&gt;
&lt;p&gt;希望这个教程能帮助你把现代后端开发的关键知识点串联起来，为后续的深入学习打下完整框架。&lt;/p&gt;
&lt;h2 id="教程技术栈选择"&gt;教程技术栈选择
&lt;/h2&gt;&lt;p&gt;入门篇将会使用 Python FastAPI SQLModel。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Python 是一门足够新手友好的后端语言，语法简单，生态丰富。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;FastAPI, SQLModel 有优秀的官方文档和新手友好设计。FastAPI 和 SQLModel 的文档本身就是足够优秀的后端教程。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在入门篇我希望尽可能减少语言上的门槛，快速讲清现代后端开发的各种基本概念，熟悉开发流程。&lt;/p&gt;
&lt;p&gt;进阶篇会使用 Go Gin GORM。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Go 语言语法简洁，可读性高，特别适合讲解底层实现和架构设计。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go 天生就很适合微服务架构，可自然过渡到更复杂的后端场景。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这一阶段，会讲解后端框架的构建原理、应用的底层设计理念，以及缓存、消息队列、微服务、云原生等更高阶的主题。&lt;/p&gt;
&lt;h2 id="教程前置知识需求"&gt;教程前置知识需求
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;掌握至少一门编程语言基础&lt;/strong&gt;。Python、JavaScript、Java、Go 都可以，但不只是会语法，更重要的是理解函数，理解类和对象，能灵活使用基础数据结构（列表、字典、集合等），理解控制流（循环、分支）、递归、异常处理。这里推荐一个十分权威的神课 &lt;a class="link" href="https://csdiy.wiki/%E7%BC%96%E7%A8%8B%E5%85%A5%E9%97%A8/Python/CS61A/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;CS61A&lt;/strong&gt;&lt;/a&gt;。本人也是通过 CS61A 打开了编程的大门。并且语言使用 Python ，和入门篇衔接上了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基础的命令行使用能力&lt;/strong&gt;。后端学习过程中会频繁接触命令行（CLI），比如：创建/进入目录、运行脚本；安装软件包、运行服务器；使用 Git 进行版本控制；修改配置文件等。虽然不是必须“精通”，但你至少要不排斥和恐惧命令行、能基本操作它。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本的英文阅读能力&lt;/strong&gt;。后端世界几乎一切文档、错误提示、API参考资料……全是英文的，本教程的 SQLModel 文档同样是英文。你不需要能流利写作或口语，但你需要：能读懂开发文档；能大致看懂报错信息；能 Google/Stack Overflow 查英文资料。如果你暂时没有练成，也不用担心，善用翻译工具就行。比如&lt;a class="link" href="https://immersivetranslate.com/zh-Hans/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;沉浸式翻译&lt;/strong&gt;&lt;/a&gt;浏览器插件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;畅通的网络环境&lt;/strong&gt;。后端开发离不开 GitHub、Stack Overflow、官方文档、npm/pip 等包管理平台。如果你不能流畅访问这些网站，找学长私聊琢磨下。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;提问的智慧&lt;/strong&gt;。你可能听说过&lt;a class="link" href="https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md" target="_blank" rel="noopener"
&gt;&lt;strong&gt;《提问的智慧》&lt;/strong&gt;&lt;/a&gt;这篇经典文章。这个文章的语气对新手有点压迫感，有种高高在上令人生畏的感觉，至少我是新手时是这么想的，看完感觉自己都不配提问了。但它确实讲的很好。虽然标题是提问的智慧，但实际上它不只是告诉你怎么问问题，更是在潜移默化地教你怎么分析问题、定位问题，最终自己解决问题，而后者我认为反而是更重要的。你可以在无聊的时候看一看这篇文章。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="如何运用本教程"&gt;如何运用本教程
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;主动学习：遇到不懂的内容时，第一步不是跳过，而是搜索、查阅文档、比对示例。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提问方法：参考&lt;a class="link" href="https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md" target="_blank" rel="noopener"
&gt;提问的智慧&lt;/a&gt;。它不仅教你如何提问，更能训练你分析、定位、并独立解决问题的能力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文档跟读：教程中会多次引导你进入官方文档查找答案，请务必自己操作，而不是只看结果。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完成作业：多数模块都会布置小作业，建议动手完成。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;拓展阅读：会提供相关资源，按需阅读以拓宽知识面。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;记录学习：建议尝试搭建自己的博客，记录每一步的思考过程和遇到的问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;团队合作项目：入门篇和进阶篇教程末尾会安排一个综合性 Project，推荐小组合作完成，以学习协作开发和项目管理，并且任务量可能不适合一个人完成。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>0.2 后端答疑篇</title><link>https://v3n0.com/post/backend-tutorial/0.2/</link><pubDate>Mon, 04 Aug 2025 02:06:14 +0800</pubDate><guid>https://v3n0.com/post/backend-tutorial/0.2/</guid><description>&lt;p&gt;这里我尽可能多地列举了小白可能想问的问题，简单的分了一下类别，列举在这里。&lt;/p&gt;
&lt;p&gt;:::warning 📌
此处的回答仅为个人观点
:::&lt;/p&gt;
&lt;p&gt;:::warning 📌
施工中
:::&lt;/p&gt;
&lt;h2 id="入门思考与自我定位"&gt;入门思考与自我定位
&lt;/h2&gt;&lt;h3 id="1-为什么学习后端"&gt;1. 为什么学习后端？
&lt;/h3&gt;&lt;p&gt;这里假设你是一个刚刚掌握了编程基础，知道类和对象等基本概念、可能完成过一些练习但缺乏完整项目经验的新手，想继续深入学习。&lt;/p&gt;
&lt;p&gt;在如果有引导、有系统学习资源，从后端开发切入项目实践，是一个很不错的选择。我会讲讲优点和缺点。&lt;/p&gt;
&lt;p&gt;学习后端会很好的&lt;strong&gt;巩固你的编程内功&lt;/strong&gt;，因为它的核心是&lt;strong&gt;逻辑，数据和架构&lt;/strong&gt;，会直接强迫你应用和深化函数、类、对象、数据结构等知识。你写的每一行代码都在处理具体的数据和逻辑流。入门后端之后，你也更容易进入云计算，DevOps，架构设计等等更进阶的领域，可以尝试“微服务”等更现代的系统构建。&lt;/p&gt;
&lt;p&gt;后端的“&lt;strong&gt;技术保质期&lt;/strong&gt;“更长。相较于前端，后端开发初期可以暂时不用理会UI设计、浏览器兼容性、页面布局以及五花八门，日新月异的前端框架。后端许多核心框架，如 Java 的 Spring、Python 的 Django，已经稳定存在十多年。近年来虽然像 Go, Rust 这种新兴语言的现代 Web 框架也开始流行，但整体来看，后端开发的核心思想变化并不大。真正变化较多的，其实是在基础设施和部署层面，比如容器化、服务网格、Serverless 等。而前端，三年前的主流技术可能放到现在已经不是最优解，导致开发者可能需要不断学习新的工具集。准确说，前端变化虽快，但并非完全“无用”，核心模型（组件化、响应式、虚拟DOM）是稳定演进的，不过也不可避免地带来开发者适应新技术的心智负担。&lt;/p&gt;
&lt;p&gt;学习后端之后，面对不同语言或框架的后端，你的&lt;strong&gt;技能可迁移性&lt;/strong&gt;会更强。API设计、数据库交互、用户认证，中间件等，这些概念在不同的语言和框架之间是通用的。而核心的业务逻辑甚至基本可以脱离特定的 Web 框架而存在。&lt;strong&gt;你会学习到通用的“道”，而不是仅仅某一个工具的“术”&lt;/strong&gt;。在技能的迁移性这一点上，后端比前端好很多。后端的核心职责是&lt;strong&gt;处理数据和执行业务规则&lt;/strong&gt;，前端的核心职责是&lt;strong&gt;管理UI状态，响应用户交互&lt;/strong&gt;。前端的业务逻辑基本等同于 UI 交互逻辑，而如何高效地管理“状态”并在状态改变时更新UI，正是每个前端框架要解决的核心问题。对于状态管理，UI渲染更新，组件通信，可能每个框架作者都充满了不同的看法，每个框架的机制都可能不同，有时甚至是哲学上的不同（比如 React 是“函数式 + 声明式”，Vue 是“模板驱动 + 响应式”），会需要你在整个思维模式上做出改变。不同的前端框架代表了不同的“道”，它们的“术”也为了各自的“道”而服务。你会需要透过现象看本质的能力，理解组件化和现代 Web 应用的构建思想，才是前端里的可迁移技能。总之，后端在早期阶段，更容易让人接触到通用的设计思想，而前端则在深入后，才逐渐显现其模型哲学和架构价值。&lt;/p&gt;
&lt;p&gt;从&lt;strong&gt;功利一点的角度&lt;/strong&gt;来看，后端在很多团队中的确&lt;strong&gt;更容易产生直接的业务价值&lt;/strong&gt;，并在&lt;strong&gt;产品形态与系统架构上拥有更多的话语权&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;比如在很多公司中，尤其是以业务驱动为主的企业，产品设计往往是后端和产品一起深度参与完成的：他们会一起确定业务流程、字段结构、权限模型等核心内容，然后由后端定义出接口，告诉前端该怎么调用。&lt;/p&gt;
&lt;p&gt;在这种分工下，前端更多是在已有接口和交互方案的基础上实现用户体验和交互逻辑，而后端则会相对而言更早介入产品设计，在架构，数据建模层面有更高参与度，包括数据模型如何抽象、流程怎么串联、接口怎么设计；系统的扩展性、可维护性、可复用性怎么保证；甚至未来支持新业务方向时的延展能力。&lt;/p&gt;
&lt;p&gt;如果你希望在产品落地中扮演更主动的角色，希望不仅是“接接口”，而是参与“设计接口”的过程，那么学习后端会让你更有这种掌控感和产出感。&lt;/p&gt;
&lt;p&gt;而从技术成长上看，后端也常常&lt;strong&gt;承担“架构演进”的主力&lt;/strong&gt;，比如服务拆分、微服务架构设计、数据库优化、系统容错等，这些都往往是后端主导的领域。因此如果你对“做更深的技术”和“参与业务底层逻辑”的方向感兴趣，后端是一个天然更贴近这些目标的位置。&lt;/p&gt;
&lt;p&gt;当然，这种角色差异也不是绝对的。在注重用户体验和复杂前端交互的项目中，比如低代码平台、图形编辑器、可视化大屏、Web IDE 等，前端也会拥有极大的设计空间和技术主导性。只是从平均情况和传统项目结构来看，后端更接近系统核心，因此也容易承担更大的设计责任和产出主力。&lt;/p&gt;
&lt;p&gt;从后端入门同样有缺点。&lt;/p&gt;
&lt;p&gt;显而易见的缺点是它&lt;strong&gt;更抽象，缺乏即时直观的反馈，入门门槛高&lt;/strong&gt;。可能你写了好多代码，却只实现了一个简单的增删改查。如果缺乏兴趣，缺乏引导，大概率会让你感到枯燥迷茫。对于编程基础较弱的同学，可能前面所说的“巩固”会变成“卡住”。相比之下，前端哪怕只是复制粘贴一个按钮，都能马上看到结果。&lt;/p&gt;
&lt;p&gt;并且想独立完成一个功能完整的后端项目，难度的确不可避免会很大。对于刚学会编程基础的新手，只写过小函数小脚本，要是看到那么复杂的项目结构，这真的令人望而却步。新手可能会花大量时间在搭环境配置，连不上库，理不清架构上。&lt;/p&gt;
&lt;p&gt;后端调试错误对于一些新手可能很困难，原因在于后端错误很多时候相对更加抽象，偏向逻辑和网络协议的错误。这些错误经常只是说：“Internal Server Error”，“Database connection refused”，“NoneType has no attribute &amp;lsquo;xyz&amp;rsquo;”，可能很难找到问题源头。而前端调试更偏UI/状态/异步交互类（虽说二者都不简单）。&lt;/p&gt;
&lt;p&gt;不过，我们的 HDU-CS-Wiki 后端教程会用最新手友好的方式，让你无痛入门后端。&lt;/p&gt;
&lt;p&gt;:::info Note
教程仍在施工，敬请期待，欢迎提供建议。
:::&lt;/p&gt;
&lt;h3 id="2-我适合后端吗"&gt;2. 我适合后端吗？
&lt;/h3&gt;&lt;p&gt;相比于一个按钮好不好看，你是否更关心它背后的系统是如何高效运转的？你是否享受分析一个问题的本质、理清逻辑结构？你是否对性能、稳定性、安全性等底层问题感兴趣？如果答案偏向于是，那么你就有成为优秀后端开发者的潜质。&lt;/p&gt;
&lt;p&gt;如果你希望在产品落地中扮演更主动的角色，希望不仅是“接接口”，而是参与“设计接口”的过程，那么学习后端会让你更有这种掌控感和产出感。&lt;/p&gt;
&lt;p&gt;如果你玩天际线，缺氧，异形工厂之类的规划类游戏，那你也很可能适合学习后端。&lt;del&gt;(夹带私货了, 因为本人也玩)&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;还有很多初学者，即使起初并不偏好后端，但希望通过项目实践掌握软件工程的通用技能，也很适合从后端开发入手，培养工程思维。也许后来你会发现后端开发的乐趣。&lt;/p&gt;
&lt;p&gt;如果你仍不确定，欢迎来群里聊聊。&lt;/p&gt;
&lt;h3 id="3-后端比前端难学吗"&gt;3. 后端比前端难学吗？
&lt;/h3&gt;&lt;p&gt;这个问题没有绝对的答案，有各自的难处，难点和节奏不同。&lt;/p&gt;
&lt;p&gt;后端门槛略高，更抽象更逻辑化，但入门之后你会感到自己在稳定扎实地前进，路线会很清晰。前端可以相对更友好地入门，但可能需要你更多广泛的涉猎，时刻紧跟动态。而且当你成为熟练的前端开发者之后，如果你想继续研究前端开发，可能你的关注点会延伸到美学、人文、可访问性等超出纯编程的领域。这需要你站在“用户视角”上去感受、思考，不是纯靠逻辑能解决的。后端则更多聚焦在数据与逻辑的构建，强调性能、可维护性、可靠性，偏向工程理性。&lt;/p&gt;
&lt;p&gt;但你如果想问这个问题，大概率你目前只打算先选一个学。这是完全可以理解的，但也要意识到：&lt;strong&gt;现代 Web 开发，前后端知识是有一定交叉的&lt;/strong&gt;。端开发者如果完全不懂前端，那和前端沟通起来会有障碍，可能不知道“这个接口怎么用才好”；前端开发者如果完全不懂后端，也可能会写出一些逻辑混乱、接口滥用的代码。真正理解前后端职责边界、协作模式的人，才能写出“干净、合理、可维护”的系统。&lt;/p&gt;
&lt;h2 id="后端的前置知识"&gt;后端的前置知识
&lt;/h2&gt;&lt;h3 id="4-学后端之前我需要先学什么"&gt;4. 学后端之前，我需要先学什么？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;掌握至少一门编程语言基础&lt;/strong&gt;。Python、JavaScript、Java、Go 都可以，但不只是会语法，更重要的是理解函数，理解类和对象，能灵活使用基础数据结构（列表、字典、集合等），理解控制流（循环、分支）、递归、异常处理。这里推荐一个十分权威的神课 &lt;a class="link" href="https://csdiy.wiki/%E7%BC%96%E7%A8%8B%E5%85%A5%E9%97%A8/Python/CS61A/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;CS61A&lt;/strong&gt;&lt;/a&gt;。本人也是通过 CS61A 打开了编程的大门。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基础的命令行使用能力&lt;/strong&gt;。后端学习过程中会频繁接触命令行（CLI），比如：创建/进入目录、运行脚本；安装软件包、运行服务器；使用 Git 进行版本控制；修改配置文件等。虽然不是必须“精通”，但你至少要不排斥和恐惧命令行、能基本操作它。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本的英文阅读能力&lt;/strong&gt;。后端世界几乎一切文档、错误提示、API参考资料……全是英文的。你不需要能流利写作或口语，但你需要：能读懂开发文档；能大致看懂报错信息；能 Google/Stack Overflow 查英文资料。如果你暂时没有练成，也不用担心，善用翻译工具就行。比如&lt;a class="link" href="https://immersivetranslate.com/zh-Hans/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;沉浸式翻译&lt;/strong&gt;&lt;/a&gt;浏览器插件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;畅通的网络环境&lt;/strong&gt;。后端开发离不开 GitHub、Stack Overflow、官方文档、npm/pip 等包管理平台。如果你不能流畅访问这些网站，找学长私聊琢磨下。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;提问的智慧&lt;/strong&gt;。你可能听说过&lt;a class="link" href="https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md" target="_blank" rel="noopener"
&gt;&lt;strong&gt;《提问的智慧》&lt;/strong&gt;&lt;/a&gt;这篇经典文章。这个文章的语气对新手有点压迫感，有种高高在上令人生畏的感觉，至少我是新手时是这么想的，看完感觉自己都不配提问了。但它确实讲的很好。虽然标题是提问的智慧，但实际上它不只是告诉你怎么问问题，更是在潜移默化地教你怎么分析问题、定位问题，最终自己解决问题，而后者我认为反而是更重要的。你可以在无聊的时候看一看这篇文章。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="5-我需要先学习前端吗"&gt;5. 我需要先学习前端吗？
&lt;/h3&gt;&lt;p&gt;不需要先学前端，完全可以直接学后端。&lt;/p&gt;
&lt;p&gt;关于这个问题其实前面的问题已经部分回答过了。这里继续梳理一遍。&lt;/p&gt;
&lt;p&gt;后端的核心任务是：处理数据、执行业务逻辑、提供接口。这套能力可以完全独立于 UI 层被开发和测试，不依赖页面渲染、按钮交互、DOM 等前端技术。也就是说，你哪怕一个 HTML 标签都没写过，也可以搭建一个能处理请求、连接数据库、执行业务逻辑的后端服务。&lt;/p&gt;
&lt;p&gt;这正是后端适合作为编程进阶路径的原因之一 —— 它能直接锤炼你的数据处理、结构设计、逻辑思维等“编程内功”。&lt;/p&gt;
&lt;p&gt;但懂一点前端，有时会帮你更好地理解前后端协作的边界。稍微了解一些 HTML/HTTP/前端如何调用 API 的方式，你会更容易理解前后端接口怎么对接，明确哪些逻辑该由后端做，哪些放在前端，或者自己写一些简单页面来测试接口，提升效率。这些都不是前置条件，而是顺带掌握、越学越通透的部分。因此 Web 前后端也不是完全分家的。你大概率两者都要涉猎一点点。&lt;/p&gt;
&lt;h3 id="6-学后端要会很多算法吗"&gt;6. 学后端要会很多算法吗？
&lt;/h3&gt;&lt;p&gt;不需要。大多数后端工作不需要你掌握大量复杂的算法，不需要你再像高中那样天天刷算法题，大多数时候用到些常规算法就行了，尤其现在各种高质量的算法库和框架早已实现了大多数通用算法，很多时候你只需要正确调用并理解其输入输出即可。&lt;/p&gt;
&lt;p&gt;因为，后端开发面对的日常问题更多的是在于工程能力、架构思维、业务理解能力，而不是实现某个图算法，手写红黑树。不过，基本的算法和数据结构知识是进阶必需的。排序、查找，哈希表、栈、队列、树、图的基本概念，时间复杂度之类的。你需要知道“这些算法大概是干什么的”，知道“何时使用它们”，而不一定要从头造轮子。&lt;/p&gt;
&lt;p&gt;算法当然是值得学的，但仅对于后端开发角度而言，是不必精通的。你对算法本身感兴趣，当然可以深入。最重要的在于你的兴趣。&lt;/p&gt;
&lt;h2 id="后端的学习路线方法资源"&gt;后端的学习路线，方法，资源
&lt;/h2&gt;&lt;h3 id="7-后端要学些啥"&gt;7. 后端要学些啥？
&lt;/h3&gt;&lt;p&gt;一开始只需要掌握一门语言 + 一个 Web 框架 + 一个数据库，能写出一个最基础的 API 服务，就已经能入门了。&lt;/p&gt;
&lt;p&gt;你只需要学会：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;怎么写接口（GET、POST、PUT、DELETE）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;怎么存数据（增删改查）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;怎么把你的服务部署起来让别人访问。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就已经是后端开发者了，真的没那么难。&lt;/p&gt;
&lt;p&gt;在此基础上，你可以逐步学地深一点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;更复杂的数据库模型（比如多表关联）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;项目结构的组织（如何让代码更清晰、可维护, 设计模式）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基础的安全（鉴权、密码加密等）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;容器化部署（Docker）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;团队协作开发（Git, Code Review）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能优化、缓存、消息队列；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;微服务，容器集群编排(kubernetes);&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些内容是可以逐步补上的，不是一开始就要全掌握。&lt;/p&gt;
&lt;p&gt;如果你想要一份更系统的大纲，欢迎关注 HDU-CS-Wiki 的后端教程。&lt;/p&gt;
&lt;h3 id="8-后端的相关教程资源"&gt;8. 后端的相关教程资源？
&lt;/h3&gt;&lt;p&gt;坦白说，如果你认真读了前面的内容，你基本已经知道你大概要学什么内容，按照什么顺序学了。&lt;/p&gt;
&lt;p&gt;但是我怕新手犯的一个错误，就是打开 B 站，搜了个后端入门，打开黑马程序员三十天速通 Spring Boot 一声不吭在那看，看着视频敲啥就照着敲啥。结果教程看完，发现离了教程就不会做了。又或者看到一半发现实在太枯燥无聊，中道崩殂。&lt;/p&gt;
&lt;p&gt;这种“填鸭式看剧”学习法听起来很安心，但实际上效率极低。你可能一晚上看了两小时，却啥也没留下来，第二天一行代码都写不出来。然后你会想，我大概需要重新看一遍教程，或者找点别的教程。这时你就陷入了教程漩涡，不能说没有进步，但是可能相对还是有点低效。而且后端更重要的不是“学某个框架”，而是学会看文档，学会调试，学会融会贯通。这也是为什么我的教程倾向于尽可能多地演示官方文档的材料的目的。&lt;/p&gt;
&lt;p&gt;读一些教学书籍未尝不可，但它需要高度的投入。一般这种书会非常详细地解释每个概念，这很棒，但也意味着进步是缓慢的，这不适用于每个人。而且大多数人不会“阅读第 x 章并完成章节后的练习”。&lt;/p&gt;
&lt;p&gt;正确的后端学习姿势是，主动探索，文档优先。&lt;/p&gt;
&lt;p&gt;我很推荐你根据自己的兴趣，用一个简单的语言和框架，跟着文档一步步直接上手尝试，尝试实现你自己想做的有趣东西。想象不到如何实现，那就直接问 AI 或者查文档。&lt;/p&gt;
&lt;p&gt;这里也推荐一些靠谱的后端课程/资源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Extensions/Server-side" target="_blank" rel="noopener"
&gt;MDN Web Doc - Server-side&lt;/a&gt; Mozilla 出品，浅显易懂，涵盖后端全貌，业界权威。&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://fastapi.tiangolo.com/zh/" target="_blank" rel="noopener"
&gt;FastAPI 官方文档&lt;/a&gt; 它虽然是框架文档，但文档作者很有开源精神，在作为框架说明文档的同时，还普及了通用的后端知识和编程知识，已经是广受好评的后端教程。Python 同时也是一个很好上手的语言，从 FastAPI 开始入门后端是相当新手友好的。&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://sqlmodel.tiangolo.com/" target="_blank" rel="noopener"
&gt;SQLModel 官方文档&lt;/a&gt; SQLModel 和 FastAPI 同作者。同样是新手友好的库，同样在文档中教学 SQL 的基础知识。&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/fastapi/full-stack-fastapi-template" target="_blank" rel="noopener"
&gt;FastAPI 全栈模板&lt;/a&gt; 在你感觉越写越乱时，可以模仿它来组织你的代码结构。拉取仓库，跑一跑玩一玩，也能顺便让你上手 Git 和 Github。&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.freecodecamp.org/" target="_blank" rel="noopener"
&gt;freeCodeCamp&lt;/a&gt; 有很多不错的免费教程。&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://sqlbolt.com/" target="_blank" rel="noopener"
&gt;SQL Bolt&lt;/a&gt; 交互式 SQL 教学，很有趣，很推荐。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你听说过 Go 语言并且想从 Go 语言上手(这会比较有挑战性)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://studygolang.gitbook.io/learn-go-with-tests" target="_blank" rel="noopener"
&gt;Learn Go with tests&lt;/a&gt; 从 Go 语言基础，到 简单的 http 应用开发，并且还教会你测试驱动开发的方法，不完全是后端教程，更多还是 Go 语言基础。&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://gowebexamples.com/" target="_blank" rel="noopener"
&gt;Go Web Examples&lt;/a&gt; 从基础到RESTful API开发&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;遇到问题时，问老登是很好的。&lt;/p&gt;
&lt;p&gt;不要被教程框住你该走的路。你要成为构建知识的人，而不是单纯的知识接受者。&lt;/p&gt;
&lt;p&gt;最后，欢迎关注 HDU-CS-Wiki 的后端教程。教程预计将分为两个部分，第一部分会用 Python FastAPI 带你简单入门后端，第二部分会由浅入深地用 Go 语言带你搭建自己的第一个大型微服务架构应用。&lt;/p&gt;
&lt;p&gt;欢迎你推荐你认为同样不错的教程。&lt;/p&gt;
&lt;h3 id="9-我要选择哪一门语言-我要选择什么框架"&gt;9. 我要选择哪一门语言？ 我要选择什么框架？
&lt;/h3&gt;&lt;p&gt;大多数时候你纠结的不是语言，而是害怕选错、走弯路。但放心讲一句：新手根本不可能选错。对于后端新手，选择简单的语言和框架即可，Python FastAPI , 或者 node.js Express 就不错。但是入门之后，也不用担心自己的技术栈不够深，而把自己定位在某一个语言，专注同一个框架。你可以拥抱各种新领域，广泛探索。因为对于后端，真正的“深入”不在于语言，而在于你是否理解背后的原理和模式。&lt;/p&gt;
&lt;h2 id="关于ai"&gt;关于AI
&lt;/h2&gt;&lt;h3 id="10-如何正确利用-ai-辅助学习"&gt;10. 如何正确利用 AI 辅助学习？
&lt;/h3&gt;&lt;p&gt;在你完全接触一个新领域时，把 AI 当作一个全天候，有耐心的私人助教。这个阶段的 AI 会极大节省你到处翻看文档查找资源的时间。并且好处在于，你永远不需要担心自己的问题是不是太蠢。你可以说：用一个生活中的例子，解释什么是RESTful API？帮我看看这段代码有什么可以优化的地方？有没有明显的不良实践？&lt;/p&gt;
&lt;p&gt;但是！如果你还没学会基础编程的各种概念，除非你已经绞尽脑汁，否则请不要将 AI 用于你的任何 &lt;strong&gt;代码练习&lt;/strong&gt; 中。这个阶段你需要的是一砖一瓦地亲手搭建最基础的知识框架。&lt;/p&gt;
&lt;p&gt;如果你已经度过了编程小白时期，开始尝试写一些自己的小项目，那么我会提出一个完全相反的观点：&lt;strong&gt;尽可能多地，放心大胆地，让 AI 来生成你的项目代码&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;不过这里的前提是，你需要&lt;strong&gt;阅读 AI 的每一行代码&lt;/strong&gt;，确保自己读懂它。并且&lt;strong&gt;调试和 debug 时不要使用 AI&lt;/strong&gt;！&lt;/p&gt;
&lt;p&gt;使用 AI 快速实现需求能极大提高你的信心，能迅速把你领进现代开发的工作流，熟悉多样的技术。同时这个阶段也完全没必要怕 AI 写的坏代码，我反而要说这是不得不品鉴的一环。只有自己第一次把坏代码写出来，你当你想改一个小功能却要动十几个地方时，你会发觉“原来这就是坏味道”，才能切实体会到代码为什么坏，才能理解某种所谓的“最佳实践”为什么是最佳实践，某些设计模式或原则为什么是好的，能借此学习如何重构自己的代码。相反，如果直接去硬啃那么多“最佳实践”，这就像是你不知道敌人是谁就举起了武器，想必是会脱靶。&lt;/p&gt;
&lt;p&gt;当你度过了这种“后新手”时期，你一定也会有自己对于 AI 工具的独特理解了。在这之前，你会从“判断 AI 写的代码好不好”开始，逐渐成为一个真正独立的开发者。&lt;/p&gt;
&lt;h3 id="11-ai-会取代后端开发吗"&gt;11. AI 会取代后端开发吗？
&lt;/h3&gt;&lt;p&gt;短期内不会。经常看到视频说完全用 AI 写了一个大项目，但目前来看， AI 的代码虽然能跑，却往往有不少问题。经常看起来 90% 正确，实际就是差那 10% 。经常缺乏架构意识和维护性考量（可以通过提示词工程来改善），或者安全性、健壮性差。&lt;/p&gt;
&lt;p&gt;但是这样来看，这也意味着 AI 的进步速度飞快，也许再过几年，AI 就能独立负责一整个项目，写出又快又好的代码。&lt;/p&gt;
&lt;p&gt;因此，后端开发者大概会需要具有架构师和产品经理的思维。&lt;/p&gt;
&lt;p&gt;AI 发达了之后，后端开发的时间成本和人力成本都会下降，更有价值的问题不再是技术本身。后端开发者可能更需要对业务有整体的把握能力。因为技术不是最终目的，&lt;strong&gt;技术的本质是为了产品服务的&lt;/strong&gt;。什么样的产品是用户所需要的，产品针对的用户群体是什么，产品的商业模式是什么，等等，可能才是更有价值的问题。&lt;/p&gt;
&lt;h2 id="关于就业"&gt;关于就业
&lt;/h2&gt;&lt;h3 id="12-青春饭35岁危机"&gt;12. 青春饭？35岁危机？
&lt;/h3&gt;&lt;p&gt;问这个问题的目的其实可能分成两个&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;可能是因为想看看未来是否还能从事计算机这个行业, 害怕跳火坑&lt;/li&gt;
&lt;li&gt;也可能是已经决定准备进入计算机行业, 但是对未来的发展比较担忧焦虑.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;关注点不同, 但焦虑的本质是相同的: 未来的不确定性.&lt;/p&gt;
&lt;p&gt;是不是有 35 岁被裁的情况呢? 的确是有的. 但是我们看问题要看本质. 行业淘汰人的原因, 不是因为年龄, 是因为性价比. 公司不会花高薪请一个拼接业务逻辑, 只会增删改查的 35 岁程序员, 但会请一个能独立承担架构、能带团队、能解决复杂问题的 35 岁工程师.&lt;/p&gt;
&lt;p&gt;年龄只是个时间点，本质是你在这段时间有没有持续成长&lt;/p&gt;
&lt;p&gt;我们从行业视角来看这个问题, 35 - 18 = 17 , 十几年时间, 足以天翻地覆. 十七年前, 互联网还没爆发, 云计算还没起步, AI 更是边缘话题. 十七年后, 谁能预测行业变成什么样?&lt;/p&gt;
&lt;p&gt;与其担忧未来这个行业会不会有危机, 不如承认计算机这个行业就是一个充满变化的行业.&lt;/p&gt;
&lt;p&gt;这里又有一个个人选择的问题. 你最终想要的到底是什么? 你是想要高薪, 还是喜欢编程, 还是想成为某个领域的专家, 还是想成为一步步爬升, 做技术管理? 想清楚之后, 你才能做准备.&lt;/p&gt;
&lt;p&gt;不过不管怎样来说, 三十五岁太遥远了, 我们更应该关注当下的事情.&lt;/p&gt;
&lt;p&gt;我能学什么，让简历上更有亮点？ 我能做什么项目，能体现解决问题的能力？ 我能利用大学的环境，去尝试哪些有趣的事情？&lt;/p&gt;
&lt;p&gt;未来不可控，当下才是你能左右的, 只有较近的未来是能被计划的.&lt;/p&gt;
&lt;h3 id="ai-发展-未来计算机是土木吗"&gt;AI 发展, 未来计算机是土木吗
&lt;/h3&gt;&lt;p&gt;首先要区分：土木和软件工程有本质上的不同。&lt;/p&gt;
&lt;p&gt;土木和软件工程不一样的地方在于, 土木改造物理世界, 软件改造数字世界. 土木有物理极限, 市场会饱和, 但软件的需求是可以膨胀的, 技术迭代速度远快于土木, 各行各业对于软件的需求是可以转移和升级, 而不会消失的. 因此软件相关的岗位大概率会在比较长的时间里一直存在.&lt;/p&gt;
&lt;p&gt;AI 在软件领域目前主要扮演的是 提效工具 的角色。它可以让开发更快，但真正要它独立完成一个大规模项目，距离现实还有差距。对于就业而言, 悲观的角度看，也许几年后 AI 的迭代能做到自动设计、自动开发、自动运维，那么传统的“低层次程序员”一定会被淘汰。&lt;/p&gt;
&lt;p&gt;但是每一波技术浪潮, 旧岗位消失的同时，新岗位也会诞生。今天 AI 火爆，Agent 开发、AI 产品设计就是新的需求；几年后，可能会出现我们现在还想不到的机会。谁知道几年之后的行业样子呢?&lt;/p&gt;
&lt;p&gt;未来的开发者门槛会提高。单纯写 CRUD 代码的价值会下降，而更需要的是&lt;strong&gt;架构师思维和产品思维&lt;/strong&gt;, 因为真正重要的不是技术, 而是业务. 技术是为了业务服务的. 用户真正需要什么？ 产品目标群体是谁？ 产品的商业模式如何？ 这些实际的业务问题，比单纯的技术实现细节更能决定一个人在公司中的不可替代性。&lt;/p&gt;</description></item><item><title>0.1 导论</title><link>https://v3n0.com/post/backend-tutorial/0.1/</link><pubDate>Sat, 02 Aug 2025 23:48:00 +0800</pubDate><guid>https://v3n0.com/post/backend-tutorial/0.1/</guid><description>&lt;blockquote&gt;
&lt;p&gt;教程作者： &lt;a class="link" href="https://v3n0.com" target="_blank" rel="noopener"
&gt;V3n0&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;欢迎阅读 Veno 的后端教程！&lt;/p&gt;
&lt;p&gt;这篇导论会快速为你建立对于整个计算机领域的认识，并让你了解后端开发在整个开发领域的位置。之后，我会尽可能浅显直白地为你解答小白对于后端的大多数疑问。如果还有更多的问题，那么欢迎提问。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="后端简介"&gt;后端简介
&lt;/h2&gt;&lt;p&gt;深入“后端”这个角色之前，我们先把镜头拉远，看看计算机领域的全貌。这是为了你能更好的理解后端是什么。&lt;/p&gt;
&lt;h3 id="计算机领域整体速通"&gt;计算机领域整体速通
&lt;/h3&gt;&lt;p&gt;我们可以把整个计算机领域想象成从零开始建造并运营一座现代化的城市：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;硬件 - 城市的基建&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是城市的根基。水电，钢筋水泥，道路交通，就是电脑的CPU, 内存，硬盘，主板等等。没有基建，城市的一切建设都是空谈。&lt;/p&gt;
&lt;p&gt;硬件是让计算成为可能的物理基础。&lt;/p&gt;
&lt;p&gt;对应到开发领域，硬件工程师负责了这些硬件的设计制造。此外还有嵌入式开发，为特定的硬件编写贴近硬件的软件（也就是固件）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;操作系统 - 城市的市政&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了利用上面的基建，我们需要有一个“市政府” &amp;ndash; &lt;strong&gt;操作系统&lt;/strong&gt;。市政府负责维护一些基础的公共服务，并且保证了城市的秩序。&lt;/p&gt;
&lt;p&gt;Windows, MacOS, Linux这些操作系统就是市政府，这是连接物理硬件与上层软件的桥梁。它们会和硬件设备交互，管理硬件资源，维持各进程有条不紊地共用资源，并提供一些公共的基础设施，比如进程管理，内存管理，文件系统，设备管理等等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;应用软件 - 城市的万千商铺&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;有了基建和市政，我们终于能开店做生意了。假设说我们想开一家大饭店。&lt;/p&gt;
&lt;p&gt;餐厅的前厅，当然就对应了 &lt;strong&gt;前端开发&lt;/strong&gt;。这是顾客能直接看到和体验到的一切。&lt;/p&gt;
&lt;p&gt;装修、菜单、桌椅、灯光、服务员，这对应着应用的用户界面（UI）。按钮长什么样，图片放在哪里，页面跳转的动画效果，点击按钮后的反应等。服务员热情地为你点餐，就如同一个友好的交互界面。&lt;/p&gt;
&lt;p&gt;而后端开发，就是餐厅的后厨。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="后端的地位"&gt;后端的地位
&lt;/h3&gt;&lt;p&gt;餐厅的后厨是顾客看不见，但决定了饭店生死存亡的核心部分。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;厨师团队 (核心业务逻辑)：&lt;/p&gt;
&lt;p&gt;他们根据菜谱（业务规则）处理食材（数据），制作出菜品（响应）。比如，用户下了一个订单，后端的厨师就要执行“减库存”、“计算价格”、“生成订单记录”等一系列操作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;仓库和货架 (数据库)：&lt;/p&gt;
&lt;p&gt;所有的食材（用户信息、商品信息、订单数据）都必须分门别类、井井有条地存放在这里。需要什么食材，厨师要能快速、准确地拿到。仓库必须安全、防盗、防火（数据安全与备份）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;点餐的小票 (API)：&lt;/p&gt;
&lt;p&gt;服务员（前端）把顾客的点单通过一个小票传到后厨（后端），后厨做好菜后，再通过这个系统通知服务员取餐。这张小票就是 API，它定义了前后端沟通的格式和语言，是连接前厅和后厨的桥梁。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;厨房的标准化装修 (后端框架):&lt;/p&gt;
&lt;p&gt;如果每个厨师都自己决定炉子放哪、案板多大、调料摆哪，后厨就会乱成一锅粥。框架就像统一装修方案：炉子、冰箱、切菜台、调料架的位置都设计好了，还配好燃气管道和下水系统。厨师（开发者）来了就能直接开工，不用自己从水电走线开始搞。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;厨师长和经理 (服务器与架构)：&lt;/p&gt;
&lt;p&gt;他要确保后厨运转高效。顾客多的时候（高并发），要加派人手（服务器扩容）；要设计好流水线（应用架构），让切菜、炒菜、洗碗协同工作；还要保证炉灶不断火（服务器稳定运行）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，后端开发就是这家饭店的“后厨团队+仓库管理员+厨师长”的集合体。&lt;/p&gt;
&lt;p&gt;他们不直接服务顾客，但他们决定了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;饭店能提供什么菜品（核心功能）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;菜品味道好不好（算法与逻辑的优劣）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;上菜速度快不快（系统性能）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;饭店能接待多少客人而不会崩溃（系统并发能力）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;客人的信息和交易安不安全（系统安全）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;看完上面的描述，你一定已经对后端是个什么很清楚了。计算机领域虽然确实很浩大，但是别被吓到。我们只需要对这个领域有一个整体的认识即可。就像是我们不需要背下百科全书，只需要学会怎样查百科全书。&lt;/p&gt;</description></item><item><title>Veno 的后端教程大纲</title><link>https://v3n0.com/post/backend-tutorial/finalized-syllabus-for-hdu-cs-wiki-backend-tutorial/</link><pubDate>Sun, 20 Jul 2025 00:21:21 +0800</pubDate><guid>https://v3n0.com/post/backend-tutorial/finalized-syllabus-for-hdu-cs-wiki-backend-tutorial/</guid><description>&lt;p&gt;2025-09-28 编辑：本人将不再参与 hdu-cs.wiki 的编辑。后端教程不会继续在 Wiki 上更新。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="before-beginning"&gt;Before Beginning
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;前置知识需求: CS61A, 或掌握至少一门编程语言（如Python）的扎实基础，理解函数、类、简单数据结构（列表、字典、集合等）、递归等核心编程概念, 畅通的网络环境, 了解Python的基础写法, 基本的英语阅读能力, 提问的艺术, 基础CLI操作&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="第一部分-后端基础-python--fastapi--sqlmodel"&gt;第一部分： 后端基础 (Python + FastAPI + SQLModel)
&lt;/h2&gt;&lt;h3 id="教学目标一"&gt;教学目标(一)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;快速上手: 让学生在几小时内，从零开始搭建起一个功能完整的 CRUD (增删改查) API。&lt;/li&gt;
&lt;li&gt;建立自信: 通过 FastAPI 强大的自动文档和 SQLModel 的易用性，让学生感受到现代工具带来的便捷，消除对后端的畏难心理。&lt;/li&gt;
&lt;li&gt;文档阅读: FastAPI 有着非常用户友好的文档, 利用它来培养阅读文档的习惯. 这也是本教程选择SQLModel而不是SQLAlchemy的原因之一&lt;/li&gt;
&lt;li&gt;正确使用AI: 不要让Copilot变成Copybot&lt;/li&gt;
&lt;li&gt;整个教程的每个模块会维护和精进同一个项目(不与 Project 1 相同, 教程项目更倾向于教学示范)&lt;/li&gt;
&lt;li&gt;理解或掌握以下知识：&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;路由函数 (Routing) 与 HTTP 方法 (GET, POST, PUT, DELETE)。&lt;/li&gt;
&lt;li&gt;SQL, ORM 与数据库操作 (CRUD)。&lt;/li&gt;
&lt;li&gt;API-服务-数据 的基本三层架构模式。&lt;/li&gt;
&lt;li&gt;中间件 (Middleware) 的作用。&lt;/li&gt;
&lt;li&gt;基本的安全思想.&lt;/li&gt;
&lt;li&gt;基本的单元测试和集成测试概念和写法&lt;/li&gt;
&lt;li&gt;配置管理: 学会分离开发, 测试, 生产环境&lt;/li&gt;
&lt;li&gt;学会现代部署: 掌握使用 Docker 和 Docker Compose 对应用进行容器化部署的基本技能。&lt;/li&gt;
&lt;li&gt;学会阅读框架文档&lt;/li&gt;
&lt;li&gt;基本的 Git 团队协作能力&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="课程大纲一"&gt;课程大纲(一)
&lt;/h3&gt;&lt;h4 id="lab-0"&gt;Lab 0
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;VSCode 配置, &lt;a class="link" href="https://fastapi.tiangolo.com/zh/python-types/" target="_blank" rel="noopener"
&gt;环境变量, Python 虚拟环境, PEP规范和类型标注&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;前后端的基本概念, 后端是什么&lt;/li&gt;
&lt;li&gt;uv Python 环境管理&lt;/li&gt;
&lt;li&gt;Git基本配置, Github&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块一-api-和-http"&gt;模块一: API 和 HTTP
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;API 和 路由函数&lt;/li&gt;
&lt;li&gt;路径参数和查询参数&lt;/li&gt;
&lt;li&gt;HTTP, GET 和 POST 方法&lt;/li&gt;
&lt;li&gt;请求体和数据校验(pydantic)&lt;/li&gt;
&lt;li&gt;API 文档 (展示FastAPI的自动生成的 Swagger 文档)&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;阅读文档, 找到如何使用 FastAPI 构造一个上传文件的接口.&lt;/li&gt;
&lt;li&gt;通过阅读文档, 发现并解决 FastAPI 中路由函数先后定义产生的问题.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;HTTP MDN, 图解HTTP&lt;/li&gt;
&lt;li&gt;RESTful API 和 WebSocket&lt;/li&gt;
&lt;li&gt;API测试工具&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块二-数据库"&gt;模块二： 数据库
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;SQL语句: 手动使用SQL来进行基础的查询和数据库操作&lt;/li&gt;
&lt;li&gt;ORM 与模型: ORM概念, 使用 SQLModel，定义第一个数据模型。&lt;/li&gt;
&lt;li&gt;连接数据库: 使用 SQLite 作为入门数据库，配置数据库连接。&lt;/li&gt;
&lt;li&gt;实现 CRUD: 编写完整的增、删、改、查四个 API 接口。&lt;/li&gt;
&lt;li&gt;数据库事务的概念和重要性(ACID), SQLModel 的 session&lt;/li&gt;
&lt;li&gt;索引设计&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;提供一个复杂的数据库 ER 图, 要求编写几个不同复杂度的 SQL 查询语句, 覆盖连接 (JOIN), 分组 (GROUP BY), 子查询等。&lt;/li&gt;
&lt;li&gt;用ORM的关系预加载优化一个 N+1 查询问题.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;SQL, NoSQL(MongoDB, Redis, Neo4j)&lt;/li&gt;
&lt;li&gt;索引, 外键, 多对多&amp;hellip;&lt;/li&gt;
&lt;li&gt;alembic 等数据库同步工具&lt;/li&gt;
&lt;li&gt;ACID、CAP 和 BASE&lt;/li&gt;
&lt;li&gt;软删除&lt;/li&gt;
&lt;li&gt;SQL 注入&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块三-代码的规范化"&gt;模块三： 代码的规范化
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;问题引入&lt;/strong&gt;: 当业务逻辑变复杂时，所有代码都写在路由函数里的坏处。&lt;/li&gt;
&lt;li&gt;重构代码: 引入三层架构思想, 把先前的代码清晰分为API层, 服务层, 路由层.&lt;/li&gt;
&lt;li&gt;如何避免过度设计&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;IoC 和 依赖注入&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://refactoringguru.cn/design-patterns/catalog" target="_blank" rel="noopener"
&gt;22种设计模式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SOLID 原则&lt;/li&gt;
&lt;li&gt;领域驱动设计&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块四-中间件"&gt;模块四： 中间件
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;中间件基本概念&lt;/li&gt;
&lt;li&gt;中间件一般应用场景&lt;/li&gt;
&lt;li&gt;错误处理中间件(统一错误响应格式)&lt;/li&gt;
&lt;li&gt;CORS中间件&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;编写一个简单的记录API日志的中间件, 统计请求处理时长.&lt;/li&gt;
&lt;li&gt;实现自定义异常处理中间件&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块五-基本的安全思想"&gt;模块五: 基本的安全思想
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;JWT Token&lt;/li&gt;
&lt;li&gt;passwd_hashed&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;环境变量管理敏感信息&lt;/li&gt;
&lt;li&gt;永远不要相信用户的输入&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;实现一个完整的注册登陆流程, 密码哈希存储&lt;/li&gt;
&lt;li&gt;利用中间件实现API的Token鉴权&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块六交付你的第一个后端服务-容器化"&gt;模块六：交付你的第一个后端服务 (容器化)
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;Docker 入门: 讲解什么是 Docker, 它解决了什么问题.&lt;/li&gt;
&lt;li&gt;Dockerfile: 为 FastAPI 应用编写一个 Dockerfile&lt;/li&gt;
&lt;li&gt;Docker Compose&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;除了Docker以外的容器, Podman, container.d&lt;/li&gt;
&lt;li&gt;CI/CD, Github Actions&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="project-1-电子书商城"&gt;Project 1: 电子书商城
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;与前端组协调, 后端小组与前端小组共同完成电子书商城项目.&lt;/li&gt;
&lt;li&gt;要求:
&lt;ul&gt;
&lt;li&gt;强制使用 Feature Branch 工作流&lt;/li&gt;
&lt;li&gt;编写有意义的 Commit Message&lt;/li&gt;
&lt;li&gt;团队成员之间需要进行 Code Review&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="第二部分-后端进阶-go--gin"&gt;第二部分： 后端进阶 (Go + Gin)
&lt;/h2&gt;&lt;h3 id="教学目标二"&gt;教学目标(二)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;深入原理: 通过 Go 的显式特性，让学生深刻理解路由、中间件、ORM 等概念的底层实现本质。&lt;/li&gt;
&lt;li&gt;培养底层思维: 从一个“框架使用者”转变为一个能思考性能、并发、内存管理的“工程师”。&lt;/li&gt;
&lt;li&gt;掌握 Go 后端开发: 熟练使用 Go 语言、Gin 框架和 GORM 来构建高性能的后端服务，并掌握 Go 的指针、错误处理等核心特性。&lt;/li&gt;
&lt;li&gt;熟悉高级组件: 使用 Redis 缓存，使用消息队列。&lt;/li&gt;
&lt;li&gt;衔接微服务架构: 理解从单体应用到微服务的演进过程，初步掌握 RPC (gRPC)、服务注册与发现、容器编排 (Kubernetes) 等核心概念。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="课程大纲二"&gt;课程大纲(二)
&lt;/h3&gt;&lt;h4 id="lab-0-go语言基础"&gt;Lab 0: Go语言基础
&lt;/h4&gt;&lt;p&gt;Go 语法, Go环境搭建, 工作区概念, Go Modules, Goroutine&lt;/p&gt;
&lt;h4 id="模块一-重新认识路由和框架"&gt;模块一： 重新认识路由和框架
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;路由的本质: 先用 Go 标准库 net/http 手写一个简单的 Web 服务器，暴露路由函数。&lt;/li&gt;
&lt;li&gt;引入 Gin: 讲解 Gin 如何用更优雅的方式解决了 net/http 的路由和分组问题。&lt;/li&gt;
&lt;li&gt;Gin 的 Context&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;尝试使用 net/http 实现一个支持不同HTTP方法的路由分发器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;gin-swagger&lt;/li&gt;
&lt;li&gt;大厂基于Gin的框架&lt;/li&gt;
&lt;li&gt;GORM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块二-再论架构与中间件的本质"&gt;模块二： 再论架构与中间件的本质
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;通过接口和构造函数手动注入依赖, 本质上为了解决相同的问题&lt;/li&gt;
&lt;li&gt;中间件的本质: 手写一个最简单的 Gin 中间件, 本质是一个接收 *gin.Context 并调用 c.Next() 的函数. 责任链模式.&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;替换Gin框架的默认Logger中间件&lt;/li&gt;
&lt;li&gt;实现一个 Panic 恢复中间件, 确保单个请求的崩溃不会导致整个服务宕机, 并能记录下崩溃的堆栈信息&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;Go的闭包&lt;/li&gt;
&lt;li&gt;go 的反射机制和适用场景&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块三-消息队列"&gt;模块三: 消息队列
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;问题引入: 当服务所需要的请求量越来越多&lt;/li&gt;
&lt;li&gt;RabbitMQ(AMQP 模型) 和 Kafka(流模型) 的区别和适用场景&lt;/li&gt;
&lt;li&gt;ACK, 持久化和重试&lt;/li&gt;
&lt;li&gt;什么时候应当为系统引入消息队列才不会显得累赘&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;实现一个异步任务, 通过API提交某个耗时请求之后, 服务将任务放入RabbitMQ后立即返回, 让一个Worker服务消费任务&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;死信队列&lt;/li&gt;
&lt;li&gt;Kafka核心概念: Topic, Partition, Offset, Consumer Group&lt;/li&gt;
&lt;li&gt;RocketMQ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块四-缓存"&gt;模块四: 缓存
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;缓存的常见策略 (Cache-aside, Read-through, Write-through)&lt;/li&gt;
&lt;li&gt;缓存穿透、缓存击穿、缓存雪崩的原因和解决方案&lt;/li&gt;
&lt;li&gt;Redis 常见数据结构的使用场景&lt;/li&gt;
&lt;li&gt;什么时候应当引入缓存才不会显得累赘&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;为某个高频读取的API增加Redis缓存(Cache-aside), 并进行压测, 对比QPS和响应时间。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;缓存与数据库一致性问题&lt;/li&gt;
&lt;li&gt;分布式锁的概念与基于Redis的实现&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块五从单体到微服务"&gt;模块五：从单体到微服务
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;单体应用的痛点, 为什么业界会需要微服务架构&lt;/li&gt;
&lt;li&gt;RPC概念, 以及RPC的底层本质&lt;/li&gt;
&lt;li&gt;gRPC: Protobuf, 服务定义, 四种通信模式, 在Go中的实践&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;创建两个微服务：user-service 和 order-service。order-service 在创建订单时，需要通过 gRPC 调用 user-service 来验证用户信息是否存在&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="模块六kubernetes"&gt;模块六：Kubernetes
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;什么是容器编排? 为什么已经有compose了还需要k8s?&lt;/li&gt;
&lt;li&gt;k8s 架构和核心概念讲解&lt;/li&gt;
&lt;li&gt;kind&lt;/li&gt;
&lt;li&gt;作业:
&lt;ul&gt;
&lt;li&gt;为一个简单的微服务编写Kubernetes的Deployment和Service的YAML文件, 并使用kind在本地部署起来&lt;/li&gt;
&lt;li&gt;在kind集群中滚动更新 (Rolling Update) 和回滚 (Rollback) 一个服务&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拓展阅读:
&lt;ul&gt;
&lt;li&gt;k8s 官方文档&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="project-2--电商平台"&gt;Project 2 : 电商平台
&lt;/h4&gt;&lt;p&gt;参考2024年字节后端青训营项目. 要求使用gRPC的微服务架构, 使用k8s集群进行部署.&lt;/p&gt;
&lt;h4 id="延伸"&gt;延伸
&lt;/h4&gt;&lt;p&gt;一起收集一下常见的各种典型后端项目的设计与实现方式.&lt;/p&gt;</description></item></channel></rss>