<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://shaozk.xyz/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https:&#x2F;&#x2F;shaozk.xyz</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It&#x27;s free.</tabi:about_feeds>
        <tabi:visit_the_site>Visit website</tabi:visit_the_site>
        <tabi:recent_posts>Recent posts</tabi:recent_posts>
        <tabi:last_updated_on>Updated on $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>cpython</tabi:current_section>
    </tabi:metadata><title>shaozk - cpython</title>
    <link href="https://shaozk.xyz/tags/cpython/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://shaozk.xyz/tags/cpython/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2026-09-06T00:00:00+00:00</updated><id>https://shaozk.xyz/tags/cpython/atom.xml</id><entry xml:lang="en">
        <title>令人困惑的 Python is 语法</title>
        <published>2026-09-06T00:00:00+00:00</published>
        <updated>2026-09-06T00:00:00+00:00</updated>
        <author>
            <name>shaozk</name>
        </author>
        <link rel="alternate" href="https://shaozk.xyz/blog/023-the-confusing-python-is-syntax/" type="text/html"/>
        <id>https://shaozk.xyz/blog/023-the-confusing-python-is-syntax/</id>
        
            <content type="html">&lt;p&gt;我们知道 Python is 语法是用于判断两个变量是否指向同一个对象，也就是说 is 会在内存层面判断否完全相同，而不仅仅是判断值是否相等。&lt;&#x2F;p&gt;
&lt;p&gt;但是...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;li-wai-qing-kuang&quot;&gt;例外情况&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;你可以自己尝试在终端输入一下，看一下结果是什么。&lt;&#x2F;p&gt;
&lt;p&gt;答案是这段代码会打印 True，然而这似乎和 is 的定义不相符合：从语法上看 a 和 b 是两个独立的变量，且值都是不可变对象字面值常量，其内存地址应该是不一样的才对。&lt;&#x2F;p&gt;
&lt;p&gt;这究竟是为什么呢？&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kai-shi-ai&quot;&gt;开始 AI&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;DeepSeek:
CPython 的小整数缓存机制，本质上是 “用空间换时间” 的优化策略：预先创建一批高频使用的小整数对象，让它们在整个解释器生命周期内被共享，避免重复创建和销毁。
缓存范围：不对称的 [-5, 256]&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;本地测试确实是如此，在 -5 到 256 的左闭右闭区间内的整数，都会产生上文提到的例外情况。而只要超出这个范围，就变“正常”了。&lt;&#x2F;p&gt;
&lt;p&gt;问题找到答案了，这是 Python 实现机制上的一个技巧，只要记住这个特性就好了。但结果真的是这样吗？&lt;&#x2F;p&gt;
&lt;h2 id=&quot;yuan-ma-zhi-qian-liao-wu-mi-mi&quot;&gt;源码之前，了无秘密&lt;&#x2F;h2&gt;
&lt;p&gt;为了加深映像，我决定查看一下 CPython 的源码实现。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;cpython&#x2F;blob&#x2F;main&#x2F;Include&#x2F;internal&#x2F;pycore_runtime_structs.h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-directive z-keyword z-control z-directive&quot;&gt;#define&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; _PY_NSMALLPOSINTS&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;           1025&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-directive z-keyword z-control z-directive&quot;&gt;#define&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; _PY_NSMALLNEGINTS&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;           5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _Py_static_objects &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;* Small integers are preallocated in this array so that they&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;         * can be shared.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;         * The integers that are preallocated are those in the range&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;         * -_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (exclusive).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;         *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        PyLongObject small_ints&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;_PY_NSMALLNEGINTS &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _PY_NSMALLPOSINTS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;* ... *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; singletons&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-directive z-keyword z-control z-directive&quot;&gt;#define&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; _Py_GLOBAL_OBJECT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    _PyRuntime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;static_objects&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-directive z-keyword z-control z-directive&quot;&gt;#define&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; _Py_SINGLETON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    _Py_GLOBAL_OBJECT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;singletons&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-directive z-keyword z-control z-directive&quot;&gt;#define&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; _PyLong_SMALL_INTS _Py_SINGLETON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;small_ints&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;static&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; PyObject &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get_small_int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;sdigit &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;ival&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    assert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;IS_SMALL_INT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;ival&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;PyObject &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;_PyLong_SMALL_INTS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;_PY_NSMALLNEGINTS &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ival&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;可以看到当值为小整数时，会直接通过 ival + 5 从预先分配好的数组中拿取数据，这也就是小整数共享内存的原因。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gen-ai-shuo-de-you-dian-bu-yi-yang&quot;&gt;跟 AI 说的有点不一样？&lt;&#x2F;h2&gt;
&lt;p&gt;等等，为啥上限值是 1025 而不是 257？最新的 CPython 已经准备将小整数范围修改为 [-5, 1024] 了。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Gemini
Python 3.13（当前稳定版） &#x2F; Python 3.14（即将发布）：没有包含此修改。它们的 _PY_NSMALLPOSINTS 依然是旧的 257，小整数池仍为 [-5, 256]。
Python 3.15（开发中版本）：已纳入。这个修改直接合并在 main 开发分支上。按照 Python 每年一个次要版本的发布节奏，包含此变动的 Python 3.15 正式版预计将于 2026 年 10 月左右发布。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;现在的时间是 2026 年 9 月 14 号，如果我不去看看源码的话，我想很难知道最新的情况。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ru-he-bi-mian&quot;&gt;如何避免&lt;&#x2F;h2&gt;
&lt;p&gt;在判断值是否相等的时候不使用 is，而是使用 ==（也应该这么做）。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ling-wai-de-yi-chong-qing-kuang&quot;&gt;另外的一种情况&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;其答案也是 True，看上去（表现）和小整数一样，但其底层原理却不相同，这里不展开。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;can-kao&quot;&gt;参考&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zackoverflow.dev&#x2F;writing&#x2F;how-often-does-python-allocate&quot;&gt;How often does Python allocate?&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        </entry>
</feed>
