<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://study-python.vercel.app/notes</id>
    <title>Study Python Blog</title>
    <updated>2026-07-18T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://study-python.vercel.app/notes"/>
    <subtitle>Study Python Blog</subtitle>
    <icon>https://study-python.vercel.app/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[装饰器深入理解：从原理到实战]]></title>
        <id>https://study-python.vercel.app/notes/decorator-deep-dive</id>
        <link href="https://study-python.vercel.app/notes/decorator-deep-dive"/>
        <updated>2026-07-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[装饰器是 Python 里「能让你代码立刻看起来很专业」的特性，也是初学者最容易卡住的坎。这篇笔记不打算抄一遍教程，而是从原理讲清楚——一旦理解了「函数就是对象」这件事，所有装饰器语法都顺理成章。]]></summary>
        <content type="html"><![CDATA[<p>装饰器是 Python 里「能让你代码立刻看起来很专业」的特性，也是初学者最容易卡住的坎。这篇笔记不打算抄一遍教程，而是从原理讲清楚——一旦理解了「函数就是对象」这件事，所有装饰器语法都顺理成章。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一原理函数就是对象">一、原理：函数就是对象<a href="https://study-python.vercel.app/notes/decorator-deep-dive#%E4%B8%80%E5%8E%9F%E7%90%86%E5%87%BD%E6%95%B0%E5%B0%B1%E6%98%AF%E5%AF%B9%E8%B1%A1" class="hash-link" aria-label="一、原理：函数就是对象的直接链接" title="一、原理：函数就是对象的直接链接" translate="no">​</a></h2>
<p>Python 里函数是一等对象（first-class object），意味着它可以：</p>
<ul>
<li class="">赋值给变量</li>
<li class="">作为参数传入</li>
<li class="">作为返回值返回</li>
<li class="">装进容器里</li>
</ul>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">greet</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"hello, </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">name</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">say </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> greet              </span><span class="token comment" style="color:#999988;font-style:italic"># 赋值给另一个名字</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"destiny"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># hello, destiny</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">funcs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">greet</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">upper</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">funcs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"world"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># hello, world</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>备注</div><div class="admonitionContent_BuS1"><p>理解装饰器的关键，不是去记 <code>@decorator</code> 的语法，而是先接受「函数就是普通的值」。后面所有装饰器都是这个事实的自然推论。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二-语法糖到底做了什么">二、@ 语法糖到底做了什么<a href="https://study-python.vercel.app/notes/decorator-deep-dive#%E4%BA%8C-%E8%AF%AD%E6%B3%95%E7%B3%96%E5%88%B0%E5%BA%95%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88" class="hash-link" aria-label="二、@ 语法糖到底做了什么的直接链接" title="二、@ 语法糖到底做了什么的直接链接" translate="no">​</a></h2>
<p>先看一个「手动」装饰的例子：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">shout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">wrapper</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">upper</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> wrapper</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"hello, </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">name</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">hello </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> shout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hello</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># 关键一步：把原函数替换成 wrapper</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"destiny"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># HELLO, DESTINY</span><br></div></code></pre></div></div>
<p><code>@shout</code> 就是上面 <code>hello = shout(hello)</code> 的语法糖：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token decorator annotation punctuation" style="color:#393A34">@shout</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"hello, </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">name</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 等价于：def hello(...): ... 然后 hello = shout(hello)</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>注意</div><div class="admonitionContent_BuS1"><p>很多教程只讲到这里就停了，但你立刻会发现一个坑：<code>hello</code> 的 <code>__name__</code> 变成了 <code>wrapper</code>，<code>help(hello)</code> 也丢了原函数的文档。这就是 <code>functools.wraps</code> 存在的理由——下一节讲。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三functoolswraps保留元信息">三、functools.wraps：保留元信息<a href="https://study-python.vercel.app/notes/decorator-deep-dive#%E4%B8%89functoolswraps%E4%BF%9D%E7%95%99%E5%85%83%E4%BF%A1%E6%81%AF" class="hash-link" aria-label="三、functools.wraps：保留元信息的直接链接" title="三、functools.wraps：保留元信息的直接链接" translate="no">​</a></h2>
<p>写装饰器永远要加 <code>@wraps</code>，否则调试时你会痛不欲生：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> functools </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> wraps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">shout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token decorator annotation punctuation" style="color:#393A34">@wraps</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">                       </span><span class="token comment" style="color:#999988;font-style:italic"># ← 关键</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">wrapper</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">upper</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> wrapper</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@shout</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""打招呼"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"hello, </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">name</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hello</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">__name__</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># hello，而不是 wrapper</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hello</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">__doc__</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 打招呼</span><br></div></code></pre></div></div>
<p><code>@wraps</code> 把原函数的 <code>__name__</code>、<code>__doc__</code>、<code>__module__</code>、<code>__wrapped__</code> 都复制到 wrapper 上，调试器、Sphinx、IDE 才能正确显示信息。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四带参数的装饰器">四、带参数的装饰器<a href="https://study-python.vercel.app/notes/decorator-deep-dive#%E5%9B%9B%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8" class="hash-link" aria-label="四、带参数的装饰器的直接链接" title="四、带参数的装饰器的直接链接" translate="no">​</a></h2>
<p>参数化装饰器本质是「多嵌一层」——外层接收参数、返回真正的装饰器：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> functools </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> wraps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">repeat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">times</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">decorator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token decorator annotation punctuation" style="color:#393A34">@wraps</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">wrapper</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> _ </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">times</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> result</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> wrapper</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> decorator</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@repeat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">times</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ping</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pong"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> end</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">" "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ping</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># pong pong pong</span><br></div></code></pre></div></div>
<p>记忆要点：<strong>普通装饰器是两层函数，带参数装饰器是三层函数</strong>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五类装饰器">五、类装饰器<a href="https://study-python.vercel.app/notes/decorator-deep-dive#%E4%BA%94%E7%B1%BB%E8%A3%85%E9%A5%B0%E5%99%A8" class="hash-link" aria-label="五、类装饰器的直接链接" title="五、类装饰器的直接链接" translate="no">​</a></h2>
<p>类也可以做装饰器，用 <code>__call__</code> 让实例可调用即可。这种写法在需要「状态」时更清晰：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CountCalls</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">__init__</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> func</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">func </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> func</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        wraps</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># 也可以保留元信息</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">__call__</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">count </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"第 </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">self</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation">count</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> 次调用"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@CountCalls</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">task</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"do work"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">task</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> task</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> task</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>也可以反过来：装饰一个类——比如自动给所有方法加 <code>@staticmethod</code>，或自动生成 <code>__repr__</code>。<code>dataclass</code> 就是典型的类装饰器。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="六常用内置装饰器速览">六、常用内置装饰器速览<a href="https://study-python.vercel.app/notes/decorator-deep-dive#%E5%85%AD%E5%B8%B8%E7%94%A8%E5%86%85%E7%BD%AE%E8%A3%85%E9%A5%B0%E5%99%A8%E9%80%9F%E8%A7%88" class="hash-link" aria-label="六、常用内置装饰器速览的直接链接" title="六、常用内置装饰器速览的直接链接" translate="no">​</a></h2>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> functools </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> lru_cache</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cached_property</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> wraps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> dataclasses </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> dataclass</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@lru_cache</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">maxsize</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">128</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic"># 自动缓存返回值，按参数缓存</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fib</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> n </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> n </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> fib</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> fib</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@dataclass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">slots</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">             </span><span class="token comment" style="color:#999988;font-style:italic"># 自动生成 __init__/__repr__/__eq__</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Point</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    x</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token decorator annotation punctuation" style="color:#393A34">@cached_property</span><span class="token plain">               </span><span class="token comment" style="color:#999988;font-style:italic"># 第一次访问后缓存，后续直接返回</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># 假设这里读文件、做计算</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1920</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1080</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@staticmethod</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> @</span><span class="token builtin">classmethod</span><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># 方法类型控制</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@property</span><span class="token plain">                          </span><span class="token comment" style="color:#999988;font-style:italic"># getter</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_BuS1"><p>3.9+ 推荐用 <code>functools.cache</code>，它等价于 <code>lru_cache(maxsize=None)</code>，无大小限制且略快。3.12 还新增了 <code>@override</code> 用于标注重写。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="七实战带参数的缓存装饰器">七、实战：带参数的缓存装饰器<a href="https://study-python.vercel.app/notes/decorator-deep-dive#%E4%B8%83%E5%AE%9E%E6%88%98%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E7%BC%93%E5%AD%98%E8%A3%85%E9%A5%B0%E5%99%A8" class="hash-link" aria-label="七、实战：带参数的缓存装饰器的直接链接" title="七、实战：带参数的缓存装饰器的直接链接" translate="no">​</a></h2>
<p>把上面的概念用起来，自己实现一个「带 TTL 的缓存」：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> functools </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> wraps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> time </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> monotonic</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> typing </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> Callable</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Any</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">cached</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ttl</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60.0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""带过期时间的缓存装饰器，单位秒。"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">decorator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Callable</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Any</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> Callable</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Any</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        store</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">dict</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Any</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        hits </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> misses </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token decorator annotation punctuation" style="color:#393A34">@wraps</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">func</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">wrapper</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">nonlocal</span><span class="token plain"> hits</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> misses</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            key </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">sorted</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            now </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> monotonic</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> key </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> store</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                ts</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> store</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> now </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> ts </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> ttl</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    hits </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> val</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">del</span><span class="token plain"> store</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            misses </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            store</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">now</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> val</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        wrapper</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cache_info </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">lambda</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">"hits"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> hits</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"misses"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> misses</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"size"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">store</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># type: ignore[attr-defined]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> wrapper</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> decorator</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@cached</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ttl</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">slow_square</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"  computing </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">x</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">..."</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> x </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> x</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">slow_square</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># computing 4... → 16</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">slow_square</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># 直接返回 16（命中缓存）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">slow_square</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cache_info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># {'hits': 1, 'misses': 1, 'size': 1}</span><br></div></code></pre></div></div>
<p>这个例子同时用到了：带参数装饰器、<code>@wraps</code>、闭包共享状态、动态给函数加属性。看懂它，装饰器就基本过关了。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结">小结<a href="https://study-python.vercel.app/notes/decorator-deep-dive#%E5%B0%8F%E7%BB%93" class="hash-link" aria-label="小结的直接链接" title="小结的直接链接" translate="no">​</a></h2>
<p>装饰器不是黑魔法，本质就一句话：<strong>用函数返回函数，用 <code>@</code> 把原函数替换掉</strong>。理解之后，去看 FastAPI 的 <code>@app.get("/")</code>、<code>pytest</code> 的 <code>@pytest.mark.parametrize</code>、Django 的 <code>@login_required</code>，会发现它们都遵循同一个套路。</p>
<p>下一篇我们会讲生成器与上下文管理器——和装饰器一样，它们也是「写出 Pythonic 代码」的三大件之一。</p>]]></content>
        <author>
            <name>Destiny</name>
            <uri>https://github.com/Destiny-GPU</uri>
        </author>
        <category label="Python" term="Python"/>
        <category label="进阶技巧" term="进阶技巧"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[用 uv 打造高效的 Python 开发工作流]]></title>
        <id>https://study-python.vercel.app/notes/uv-workflow</id>
        <link href="https://study-python.vercel.app/notes/uv-workflow"/>
        <updated>2026-07-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[如果你还在用 python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt 这套三连击，那么这篇文章会改变你的工作流。本教程默认使用 uv 作为依赖管理工具，本文解释为什么，以及怎么用。]]></summary>
        <content type="html"><![CDATA[<p>如果你还在用 <code>python -m venv .venv &amp;&amp; source .venv/bin/activate &amp;&amp; pip install -r requirements.txt</code> 这套三连击，那么这篇文章会改变你的工作流。本教程默认使用 <strong>uv</strong> 作为依赖管理工具，本文解释为什么，以及怎么用。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一uv-是什么">一、uv 是什么<a href="https://study-python.vercel.app/notes/uv-workflow#%E4%B8%80uv-%E6%98%AF%E4%BB%80%E4%B9%88" class="hash-link" aria-label="一、uv 是什么的直接链接" title="一、uv 是什么的直接链接" translate="no">​</a></h2>
<p><a href="https://github.com/astral-sh/uv" target="_blank" rel="noopener noreferrer" class="">uv</a> 是 Astral 公司（也就是做 Ruff 那家）用 Rust 写的 Python 包管理工具，定位上同时是：</p>
<ul>
<li class=""><code>pip</code> 的替代（安装包，但快 10–100 倍）</li>
<li class=""><code>venv</code> 的替代（一行命令创建虚拟环境）</li>
<li class=""><code>pip-tools</code> 的替代（依赖锁定、解析）</li>
<li class=""><code>poetry</code> / <code>rye</code> / <code>pyenv</code> 的部分替代（项目管理、Python 版本管理）</li>
</ul>
<p>它的核心卖点是<strong>快</strong>——快到你会怀疑「是不是没装上」。</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_BuS1"><p>uv 的设计哲学是「兼容现有生态」：它依然生成标准的 <code>pyproject.toml</code>、<code>requirements.txt</code>、<code>uv.lock</code>，你随时可以退回用 pip，不会被困住。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二为什么选择-uv">二、为什么选择 uv<a href="https://study-python.vercel.app/notes/uv-workflow#%E4%BA%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-uv" class="hash-link" aria-label="二、为什么选择 uv的直接链接" title="二、为什么选择 uv的直接链接" translate="no">​</a></h2>
<p>我之前用 poetry，后来转 rye，最后定在 uv。理由有三个：</p>
<ol>
<li class=""><strong>速度</strong>：装一个 Django 项目，pip 要 30 秒，uv 只要 3 秒。开发体验直接质变。</li>
<li class=""><strong>一个工具搞定一切</strong>：装 Python、建虚拟环境、装包、跑脚本、锁定依赖，全部一个命令搞定，不用 <code>pyenv</code> + <code>venv</code> + <code>pip</code> 三件套。</li>
<li class=""><strong>全局工具安装</strong>：<code>uv tool install ruff</code> 装全局 CLI 工具，类似 <code>pipx</code>，比 npm 全局装包还顺手。</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三核心命令速查">三、核心命令速查<a href="https://study-python.vercel.app/notes/uv-workflow#%E4%B8%89%E6%A0%B8%E5%BF%83%E5%91%BD%E4%BB%A4%E9%80%9F%E6%9F%A5" class="hash-link" aria-label="三、核心命令速查的直接链接" title="三、核心命令速查的直接链接" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python 版本管理</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv python </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3.12</span><span class="token plain">          </span><span class="token comment" style="color:#999988;font-style:italic"># 安装 Python 3.12</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv python list                  </span><span class="token comment" style="color:#999988;font-style:italic"># 列出可用版本</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 虚拟环境（也兼容旧用法）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv venv                         </span><span class="token comment" style="color:#999988;font-style:italic"># 在当前目录创建 .venv</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv venv </span><span class="token parameter variable" style="color:#36acaa">--python</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3.12</span><span class="token plain">           </span><span class="token comment" style="color:#999988;font-style:italic"># 指定 Python 版本</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 包管理（pip 的替代）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv pip </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> requests          </span><span class="token comment" style="color:#999988;font-style:italic"># 装 pip 包</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv pip </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-r</span><span class="token plain"> requirements.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv pip list</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 项目管理（推荐用法，替代 poetry）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv init my-project              </span><span class="token comment" style="color:#999988;font-style:italic"># 初始化一个新项目</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> fastapi                  </span><span class="token comment" style="color:#999988;font-style:italic"># 加依赖到 pyproject.toml</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--dev</span><span class="token plain"> pytest             </span><span class="token comment" style="color:#999988;font-style:italic"># 加开发依赖</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv remove fastapi               </span><span class="token comment" style="color:#999988;font-style:italic"># 移除依赖</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv </span><span class="token function" style="color:#d73a49">sync</span><span class="token plain">                          </span><span class="token comment" style="color:#999988;font-style:italic"># 按 lockfile 安装/同步环境</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv lock                          </span><span class="token comment" style="color:#999988;font-style:italic"># 重新解析依赖生成 uv.lock</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv run python main.py           </span><span class="token comment" style="color:#999988;font-style:italic"># 在项目环境里跑命令（自动 sync）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv run pytest                    </span><span class="token comment" style="color:#999988;font-style:italic"># 跑测试</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>备注</div><div class="admonitionContent_BuS1"><p><code>uv pip install</code> 和 <code>uv add</code> 是两个层次的东西：前者只是「快速版 pip」，不动 <code>pyproject.toml</code>；后者会把依赖写进项目配置并更新 <code>uv.lock</code>。在项目里优先用 <code>uv add</code>。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四与-pip--venv--poetry-的对比">四、与 pip / venv / poetry 的对比<a href="https://study-python.vercel.app/notes/uv-workflow#%E5%9B%9B%E4%B8%8E-pip--venv--poetry-%E7%9A%84%E5%AF%B9%E6%AF%94" class="hash-link" aria-label="四、与 pip / venv / poetry 的对比的直接链接" title="四、与 pip / venv / poetry 的对比的直接链接" translate="no">​</a></h2>
<table><thead><tr><th>能力</th><th>pip + venv</th><th>poetry</th><th>uv</th></tr></thead><tbody><tr><td>速度</td><td>慢</td><td>慢</td><td>极快</td></tr><tr><td>虚拟环境</td><td>手动</td><td>自动</td><td>自动</td></tr><tr><td>依赖锁定</td><td>需 pip-tools</td><td>内置</td><td>内置</td></tr><tr><td>Python 版本管理</td><td>不支持</td><td>不支持</td><td>支持</td></tr><tr><td>全局工具安装</td><td>需 pipx</td><td>不支持</td><td>支持</td></tr><tr><td>兼容 pyproject.toml</td><td>部分</td><td>是</td><td>是</td></tr></tbody></table>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>注意</div><div class="admonitionContent_BuS1"><p>poetry 的 lock 文件解析在某些场景下会比较慢，且对私有源支持较弱。如果你的项目依赖很多、CI 跑得很频繁，迁移到 uv 后构建时间通常能减半。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五实战用-uv-创建一个完整项目">五、实战：用 uv 创建一个完整项目<a href="https://study-python.vercel.app/notes/uv-workflow#%E4%BA%94%E5%AE%9E%E6%88%98%E7%94%A8-uv-%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%AE%8C%E6%95%B4%E9%A1%B9%E7%9B%AE" class="hash-link" aria-label="五、实战：用 uv 创建一个完整项目的直接链接" title="五、实战：用 uv 创建一个完整项目的直接链接" translate="no">​</a></h2>
<p>下面用 uv 把本教程里的一个 demo 项目跑起来：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 1. 初始化项目</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv init study-demo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin class-name">cd</span><span class="token plain"> study-demo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 2. 指定 Python 版本并创建环境</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv python pin </span><span class="token number" style="color:#36acaa">3.12</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 3. 加入生产依赖</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> fastapi </span><span class="token string" style="color:#e3116c">'uvicorn[standard]'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> httpx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 4. 加入开发依赖</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--dev</span><span class="token plain"> pytest pytest-asyncio ruff</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 5. 跑起来（不需要手动 activate，uv run 自动处理）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv run uvicorn main:app </span><span class="token parameter variable" style="color:#36acaa">--reload</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 6. 跑测试</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv run pytest </span><span class="token parameter variable" style="color:#36acaa">-v</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 7. 别人 clone 项目后，只要一句</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv </span><span class="token function" style="color:#d73a49">sync</span><br></div></code></pre></div></div>
<p>执行完，项目结构长这样：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">study-demo/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── .python-version    # uv python pin 写入</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── .venv/             # uv venv 自动创建</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── pyproject.toml     # uv init 生成，uv add 维护</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── uv.lock            # uv lock 生成，锁定所有依赖</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── README.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── src/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── study_demo/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        └── __init__.py</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_BuS1"><p>把 <code>.venv/</code> 加进 <code>.gitignore</code>，但<strong>一定要把 <code>uv.lock</code> 提交到 git</strong>。lockfile 是保证「同事和我装的是同一套版本」的关键，千万别忽略它。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="六与现有-requirementstxt-项目共存">六、与现有 requirements.txt 项目共存<a href="https://study-python.vercel.app/notes/uv-workflow#%E5%85%AD%E4%B8%8E%E7%8E%B0%E6%9C%89-requirementstxt-%E9%A1%B9%E7%9B%AE%E5%85%B1%E5%AD%98" class="hash-link" aria-label="六、与现有 requirements.txt 项目共存的直接链接" title="六、与现有 requirements.txt 项目共存的直接链接" translate="no">​</a></h2>
<p>uv 不强制你迁移。如果是老项目，可以这样平滑过渡：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 老 requirements.txt 直接同步</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv venv</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uv pip </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-r</span><span class="token plain"> requirements.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 之后再慢慢迁移到 uv add / pyproject.toml</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结">小结<a href="https://study-python.vercel.app/notes/uv-workflow#%E5%B0%8F%E7%BB%93" class="hash-link" aria-label="小结的直接链接" title="小结的直接链接" translate="no">​</a></h2>
<p>uv 不是「又一个包管理器」，而是把 <code>pyenv + venv + pip + pip-tools + pipx</code> 这一堆工具用 Rust 重写并整合成一个二进制。装上之后，我再也不用记忆「这个项目用 poetry，那个项目用 pipenv」——统一用 uv 就够了。</p>
<p>下一篇我们正式进入 Python 语法本身，从最基础的变量和类型注解开始。</p>]]></content>
        <author>
            <name>Destiny</name>
            <uri>https://github.com/Destiny-GPU</uri>
        </author>
        <category label="Python" term="Python"/>
        <category label="工具" term="工具"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[现代 Python 你应该知道的 10 个特性]]></title>
        <id>https://study-python.vercel.app/notes/modern-python-features</id>
        <link href="https://study-python.vercel.app/notes/modern-python-features"/>
        <updated>2026-07-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[很多人写 Python 还停留在 3.6 时代的写法：Optional[int]、os.path.join、if-elif-else 一长串。其实从 3.10 开始，Python 已经悄悄变成了一门「看起来很像新语言」的语言。下面这 10 个特性，是我在日常代码里几乎天天都会用到的。本教程默认 Python 3.12+，所以放心大胆地用。]]></summary>
        <content type="html"><![CDATA[<p>很多人写 Python 还停留在 3.6 时代的写法：<code>Optional[int]</code>、<code>os.path.join</code>、<code>if-elif-else</code> 一长串。其实从 3.10 开始，Python 已经悄悄变成了一门「看起来很像新语言」的语言。下面这 10 个特性，是我在日常代码里几乎天天都会用到的。本教程默认 Python 3.12+，所以放心大胆地用。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-match-case结构化模式匹配310">1. match-case：结构化模式匹配（3.10）<a href="https://study-python.vercel.app/notes/modern-python-features#1-match-case%E7%BB%93%E6%9E%84%E5%8C%96%E6%A8%A1%E5%BC%8F%E5%8C%B9%E9%85%8D310" class="hash-link" aria-label="1. match-case：结构化模式匹配（3.10）的直接链接" title="1. match-case：结构化模式匹配（3.10）的直接链接" translate="no">​</a></h2>
<p>不再是简单的 switch，它支持解构：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">describe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">match</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"原点"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"在 x 轴上，x=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">x</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"在 y 轴上，y=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">y</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"普通点 (</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">x</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">, </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">y</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">)"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">describe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 在 x 轴上，x=3</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_BuS1"><p><code>match-case</code> 还能匹配类实例、字典、序列，配合「守卫表达式」(<code>case Point(x, y) if x == y</code>) 非常强大。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-海象运算符-38但-310-才流行起来">2. 海象运算符 <code>:=</code>（3.8，但 3.10 才流行起来）<a href="https://study-python.vercel.app/notes/modern-python-features#2-%E6%B5%B7%E8%B1%A1%E8%BF%90%E7%AE%97%E7%AC%A6-38%E4%BD%86-310-%E6%89%8D%E6%B5%81%E8%A1%8C%E8%B5%B7%E6%9D%A5" class="hash-link" aria-label="2-海象运算符-38但-310-才流行起来的直接链接" title="2-海象运算符-38但-310-才流行起来的直接链接" translate="no">​</a></h2>
<p>赋值的同时返回值，省掉一次重复调用：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> re</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">m </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> re</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">search</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">r"\d+"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"订单号: 9527"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">is</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">not</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"提取到数字：</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">m</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation">group</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 提取到数字：9527</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-类型注解-x--y310">3. 类型注解 <code>X | Y</code>（3.10）<a href="https://study-python.vercel.app/notes/modern-python-features#3-%E7%B1%BB%E5%9E%8B%E6%B3%A8%E8%A7%A3-x--y310" class="hash-link" aria-label="3-类型注解-x--y310的直接链接" title="3-类型注解-x--y310的直接链接" translate="no">​</a></h2>
<p>终于不用再写 <code>Union[int, str]</code> 和 <code>Optional[int]</code>：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">find_user</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">user_id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">dict</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> user_id </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">"name"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"destiny"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 等价于 Optional[dict] / Union[dict, None]</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-dataclass--slots310">4. dataclass + slots（3.10）<a href="https://study-python.vercel.app/notes/modern-python-features#4-dataclass--slots310" class="hash-link" aria-label="4. dataclass + slots（3.10）的直接链接" title="4. dataclass + slots（3.10）的直接链接" translate="no">​</a></h2>
<p>一行 <code>slots=True</code> 让 dataclass 用 <code>__slots__</code>，省内存又禁止动态属性：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> dataclasses </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> dataclass</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@dataclass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">slots</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Point</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    x</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">p </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2.0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># p.z = 3.0  # AttributeError，防止手滑加错字段</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-f-string-嵌套与调试输出312">5. f-string 嵌套与调试输出（3.12）<a href="https://study-python.vercel.app/notes/modern-python-features#5-f-string-%E5%B5%8C%E5%A5%97%E4%B8%8E%E8%B0%83%E8%AF%95%E8%BE%93%E5%87%BA312" class="hash-link" aria-label="5. f-string 嵌套与调试输出（3.12）的直接链接" title="5. f-string 嵌套与调试输出（3.12）的直接链接" translate="no">​</a></h2>
<p>3.12 终于支持在 f-string 的 <code>{}</code> 里再写 f-string，<code>=调试语法</code>也更好用：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">user </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">"name"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"destiny"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"level"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">12</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 嵌套 f-string</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"{f"</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">user</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'name'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">:</span><span class="token operator" style="color:#393A34">^</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">width</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token string" style="color:#e3116c">"}"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">#    destiny</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 调试语法 = 直接打印变量名和值</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">user</span><span class="token string-interpolation interpolation operator" style="color:#393A34">=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># user={'name': 'destiny', 'level': 5}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-taskgroup结构化并发311">6. TaskGroup：结构化并发（3.11）<a href="https://study-python.vercel.app/notes/modern-python-features#6-taskgroup%E7%BB%93%E6%9E%84%E5%8C%96%E5%B9%B6%E5%8F%91311" class="hash-link" aria-label="6. TaskGroup：结构化并发（3.11）的直接链接" title="6. TaskGroup：结构化并发（3.11）的直接链接" translate="no">​</a></h2>
<p><code>asyncio.gather</code> 的更安全替代，子任务出错能一起取消：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> asyncio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> asyncio</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0.1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"data from </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">url</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">with</span><span class="token plain"> asyncio</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">TaskGroup</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> tg</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        t1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">create_task</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"api/a"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        t2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">create_task</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"api/b"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">asyncio</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>注意</div><div class="admonitionContent_BuS1"><p><code>TaskGroup</code> 一旦有任何子任务抛错，会取消其它所有子任务，并抛出 <code>ExceptionGroup</code>。这正是我们想要的行为——并发任务要么一起成功，要么一起失败。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-exceptiongroup--except311">7. ExceptionGroup / except*（3.11）<a href="https://study-python.vercel.app/notes/modern-python-features#7-exceptiongroup--except311" class="hash-link" aria-label="7. ExceptionGroup / except*（3.11）的直接链接" title="7. ExceptionGroup / except*（3.11）的直接链接" translate="no">​</a></h2>
<p>为并发场景设计的「一组异常一起处理」：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">risky</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> x </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">raise</span><span class="token plain"> ValueError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"负数：</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">x</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    risky</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    risky</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">except</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ValueError </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> eg</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> e </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> eg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exceptions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"处理："</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="8-type-语句定义类型别名312">8. <code>type</code> 语句：定义类型别名（3.12）<a href="https://study-python.vercel.app/notes/modern-python-features#8-type-%E8%AF%AD%E5%8F%A5%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D312" class="hash-link" aria-label="8-type-语句定义类型别名312的直接链接" title="8-type-语句定义类型别名312的直接链接" translate="no">​</a></h2>
<p><code>TypeAlias</code> 的语法糖，还能定义泛型别名：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token builtin">type</span><span class="token plain"> Vector </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">list</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">type</span><span class="token plain"> Matrix</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">list</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">list</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">norm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">v</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Vector</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token builtin">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> x </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> x </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">**</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 泛型别名</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Matrix</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="9-pathlibpathwalk312">9. <code>pathlib.Path.walk()</code>（3.12）<a href="https://study-python.vercel.app/notes/modern-python-features#9-pathlibpathwalk312" class="hash-link" aria-label="9-pathlibpathwalk312的直接链接" title="9-pathlibpathwalk312的直接链接" translate="no">​</a></h2>
<p>终于不用再写 <code>os.walk</code>，而且能拿到 <code>dir_entry</code> 做更高效过滤：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> pathlib </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> Path</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Path</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"."</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> dirpath</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> dirnames</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> filenames </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">walk</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"__pycache__"</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> dirnames</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        dirnames</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"__pycache__"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 剪枝，不再深入</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> name </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> filenames</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">endswith</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">".py"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dirpath </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_BuS1"><p><code>Path.walk()</code> 还支持 <code>top_down=False</code>，自底向上遍历——删空目录时非常有用。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="10-self-类型--override-装饰器311312">10. Self 类型 &amp; <code>override</code> 装饰器（3.11/3.12）<a href="https://study-python.vercel.app/notes/modern-python-features#10-self-%E7%B1%BB%E5%9E%8B--override-%E8%A3%85%E9%A5%B0%E5%99%A8311312" class="hash-link" aria-label="10-self-类型--override-装饰器311312的直接链接" title="10-self-类型--override-装饰器311312的直接链接" translate="no">​</a></h2>
<p>写「返回自己类型」的方法不再痛苦：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> typing </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> Self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> override</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Shape</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">scale</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> factor</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> Self</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> self  </span><span class="token comment" style="color:#999988;font-style:italic"># 子类调用会自动返回子类类型</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Circle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Shape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">__init__</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">r </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> r</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token decorator annotation punctuation" style="color:#393A34">@override</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">scale</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> factor</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> Self</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">r </span><span class="token operator" style="color:#393A34">*=</span><span class="token plain"> factor</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> self</span><br></div></code></pre></div></div>
<p><code>@override</code> 会在父类没有同名方法时静态报错，防止手滑写错方法名。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="小结">小结<a href="https://study-python.vercel.app/notes/modern-python-features#%E5%B0%8F%E7%BB%93" class="hash-link" aria-label="小结的直接链接" title="小结的直接链接" translate="no">​</a></h2>
<p>这 10 个特性里，<strong>真正改变我写代码习惯</strong>的是三个：<code>match-case</code>（替代 if-elif 链）、<code>X | Y</code> 类型注解（让类型写起来不痛苦）、<code>TaskGroup</code>（让并发代码更安全）。其余几个则是「锦上添花」，但堆在一起，已经让 Python 3.12 读起来像一门全新的语言。</p>
<p>如果你还在用 3.9 写代码，强烈建议升级到 3.12——体验的提升不只是「快一点」，而是「写法完全不同」。</p>]]></content>
        <author>
            <name>Destiny</name>
            <uri>https://github.com/Destiny-GPU</uri>
        </author>
        <category label="Python" term="Python"/>
        <category label="进阶技巧" term="进阶技巧"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[我的 Python 学习路径规划]]></title>
        <id>https://study-python.vercel.app/notes/python-learning-path</id>
        <link href="https://study-python.vercel.app/notes/python-learning-path"/>
        <updated>2026-07-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[学一门语言，最难的不是语法，而是不知道「下一步该学什么」。我最初学 Python 时，把官方教程从头读到尾，结果读完依旧写不出一个像样的项目。后来我换了思路：先建立地图，再按图索骥地走，效率立刻翻倍。这篇文章就是我的那张地图，也是本教程的章节骨架。]]></summary>
        <content type="html"><![CDATA[<p>学一门语言，最难的不是语法，而是不知道「下一步该学什么」。我最初学 Python 时，把官方教程从头读到尾，结果读完依旧写不出一个像样的项目。后来我换了思路：<strong>先建立地图，再按图索骥地走</strong>，效率立刻翻倍。这篇文章就是我的那张地图，也是本教程的章节骨架。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一为什么需要一份学习路径">一、为什么需要一份「学习路径」<a href="https://study-python.vercel.app/notes/python-learning-path#%E4%B8%80%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E4%B8%80%E4%BB%BD%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84" class="hash-link" aria-label="一、为什么需要一份「学习路径」的直接链接" title="一、为什么需要一份「学习路径」的直接链接" translate="no">​</a></h2>
<p>Python 的知识面非常宽：可以做 Web、可以搞数据、可以写脚本、可以搞运维。如果没有路径，很容易陷入「今天看一点爬虫，明天看一点 Django」的碎片化学习，半年下来什么都没学透。</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>备注</div><div class="admonitionContent_BuS1"><p>学习路径不是要把所有东西都学完，而是让你在任意时刻都知道「我现在在哪、下一步去哪」。一旦有了坐标系，每一份新知识都能挂到合适的分支上。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二本教程的章节结构">二、本教程的章节结构<a href="https://study-python.vercel.app/notes/python-learning-path#%E4%BA%8C%E6%9C%AC%E6%95%99%E7%A8%8B%E7%9A%84%E7%AB%A0%E8%8A%82%E7%BB%93%E6%9E%84" class="hash-link" aria-label="二、本教程的章节结构的直接链接" title="二、本教程的章节结构的直接链接" translate="no">​</a></h2>
<p>我把整个学习过程拆成五个阶段，由浅入深：</p>
<ol>
<li class=""><strong>基础语法</strong>：变量、数据类型、控制流、函数。目标是能独立写出 50 行以内的小工具。</li>
<li class=""><strong>面向对象与模块化</strong>：类、继承、组合、模块、包。理解 <code>import</code> 背后到底发生了什么。</li>
<li class=""><strong>进阶特性</strong>：装饰器、生成器、上下文管理器、类型注解。这是「写出 Pythonic 代码」的分水岭。</li>
<li class=""><strong>工程化能力</strong>：虚拟环境、依赖管理（uv）、测试（pytest）、项目结构。让你写的代码能给别人用。</li>
<li class=""><strong>领域深入</strong>：选一个方向（Web / 数据 / 自动化）深耕，把前面四阶段的知识用到真实场景里。</li>
</ol>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_BuS1"><p>不要跳过第 3 阶段。很多初学者觉得「能跑就行」，但装饰器和生成器恰恰是阅读优秀开源代码的门槛。跳过它们，你看不懂 FastAPI、看不懂 Django ORM，也写不出优雅的工具。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三循序渐进的方法论">三、循序渐进的方法论<a href="https://study-python.vercel.app/notes/python-learning-path#%E4%B8%89%E5%BE%AA%E5%BA%8F%E6%B8%90%E8%BF%9B%E7%9A%84%E6%96%B9%E6%B3%95%E8%AE%BA" class="hash-link" aria-label="三、循序渐进的方法论的直接链接" title="三、循序渐进的方法论的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-用输出倒逼输入">1. 用「输出」倒逼「输入」<a href="https://study-python.vercel.app/notes/python-learning-path#1-%E7%94%A8%E8%BE%93%E5%87%BA%E5%80%92%E9%80%BC%E8%BE%93%E5%85%A5" class="hash-link" aria-label="1. 用「输出」倒逼「输入」的直接链接" title="1. 用「输出」倒逼「输入」的直接链接" translate="no">​</a></h3>
<p>每学一个特性，立刻写一段代码验证。比如学到 <code>dataclass</code>，就试着把家里的书架建模出来：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> dataclasses </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> dataclass</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> field</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#393A34">@dataclass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">slots</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Book</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    title</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    author</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    tags</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">list</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> field</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">default_factory</span><span class="token operator" style="color:#393A34">=</span><span class="token builtin">list</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">summary</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"《</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">self</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation">title</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">》—— </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">self</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation">author</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">shelf </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">Book</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"流畅的 Python"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Luciano Ramalho"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Book</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Python Cookbook"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"David Beazley"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> book </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> shelf</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">book</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">summary</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>写完这段代码，你对 <code>dataclass</code>、类型注解、<code>field</code> 默认值、<code>slots</code> 的理解会立刻立体起来。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-三次重复原则">2. 「三次重复」原则<a href="https://study-python.vercel.app/notes/python-learning-path#2-%E4%B8%89%E6%AC%A1%E9%87%8D%E5%A4%8D%E5%8E%9F%E5%88%99" class="hash-link" aria-label="2. 「三次重复」原则的直接链接" title="2. 「三次重复」原则的直接链接" translate="no">​</a></h3>
<p>一个知识点，至少在三个不同场景下用过，才算真正掌握。比如 <code>pathlib.Path</code>：</p>
<ul>
<li class="">第一次：读一个配置文件；</li>
<li class="">第二次：批量重命名目录下的图片；</li>
<li class="">第三次：在单元测试里构造临时目录。</li>
</ul>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>注意</div><div class="admonitionContent_BuS1"><p>最常见的失败模式是「教程疲劳」——连续看几个小时视频却不动手。我的建议：每 30 分钟必须写一段代码，哪怕只是把教程里的例子敲一遍。手感是练出来的，不是看出来的。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四给学习者的三条建议">四、给学习者的三条建议<a href="https://study-python.vercel.app/notes/python-learning-path#%E5%9B%9B%E7%BB%99%E5%AD%A6%E4%B9%A0%E8%80%85%E7%9A%84%E4%B8%89%E6%9D%A1%E5%BB%BA%E8%AE%AE" class="hash-link" aria-label="四、给学习者的三条建议的直接链接" title="四、给学习者的三条建议的直接链接" translate="no">​</a></h2>
<p><strong>第一，版本不要太旧。</strong> 本教程默认 Python 3.12+，因为 <code>match-case</code>、<code>type</code> 语句、<code>TaskGroup</code> 这些特性会显著改变你的写法。在新版本上学习，能少走很多弯路。</p>
<p><strong>第二，读源码比看教程更重要。</strong> 当你掌握基础后，挑一个体量适中的库（比如 <code>rich</code>、<code>httpx</code>）通读它的源码，你会看到真正的工程代码长什么样。</p>
<p><strong>第三，建立自己的「错误笔记本」。</strong> 每次踩坑都记录下来：报错信息、原因、解决方法。三个月后回看，你会发现自己已经迈过了一个又一个坎。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五下一步">五、下一步<a href="https://study-python.vercel.app/notes/python-learning-path#%E4%BA%94%E4%B8%8B%E4%B8%80%E6%AD%A5" class="hash-link" aria-label="五、下一步的直接链接" title="五、下一步的直接链接" translate="no">​</a></h2>
<p>我会按上面的五阶段，逐步更新本教程的每一章。如果你也刚好在学 Python，欢迎跟着笔记一起走。我们慢慢来，但每一步都走扎实。</p>
<blockquote>
<p>学习不是赛跑，是长途徒步。重要的不是今天走了多远，而是明天还想继续走。</p>
</blockquote>]]></content>
        <author>
            <name>Destiny</name>
            <uri>https://github.com/Destiny-GPU</uri>
        </author>
        <category label="Python" term="Python"/>
        <category label="学习心得" term="学习心得"/>
    </entry>
</feed>