<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
>
<channel>
<title><![CDATA[个人知识分享小站]]></title> 
<atom:link href="https://www.fsgoa.com/rss.php" rel="self" type="application/rss+xml" />
<description><![CDATA[WELCOME TO MY WEB]]></description>
<link>https://www.fsgoa.com/</link>
<language>zh-cn</language>
<generator>www.emlog.net</generator>
<item>
    <title>系统开发全流程具备充足的安全性、稳定性与可靠性用建筑的类比进行理解</title>
    <link>https://www.fsgoa.com/?post=19</link>
    <description><![CDATA[<p>若将“系统开发全流程的安全性、稳定性与可靠性”类比为“建筑建造全流程”，可通过建筑从“规划设计→材料选型→施工建造→验收运维”的完整生命周期，对应系统开发的核心环节，让抽象的技术要求转化为直观的建筑逻辑，具体类比如下：</p>
<h3>一、系统开发“需求分析与安全规划”→ 建筑“地质勘察与安全设计”</h3>
<p>建筑的安全与稳定，始于对“地基环境”的精准判断——需勘察地质结构（如土壤承载力、地震烈度），明确建筑用途（住宅/医院/超高层），再制定核心安全标准（如抗震等级、防火规范）。<br />
对应系统开发：需求分析阶段需像建筑勘察一样，先明确系统“业务场景”（如政务服务/敏感数据管理）、“风险环境”（如是否暴露公网、是否存储个人信息），再制定安全目标（如数据加密要求、访问控制规则）。例如三级政务系统需满足“等保三级”，如同医院建筑需满足“抗震8级+防火一级”的特殊标准，这是全流程安全的“底层依据”。</p>
<h3>二、系统开发“架构设计与安全防护”→ 建筑“结构设计与防护体系”</h3>
<p>建筑的稳定性依赖“核心结构”与“防护层”：  </p>
<ul>
<li>核心结构：如高层建筑的“钢筋混凝土框架”，需承载垂直荷载与水平风压，对应系统的“架构设计”（如多层架构分离业务逻辑与数据层、微服务拆分降低单点风险），避免某一模块故障影响整体；  </li>
<li>防护体系：如建筑的“防火墙（实体防火分区）、防盗门窗、防雷接地”，对应系统的“安全机制”（如接口鉴权、数据加密、入侵检测）。例如二级系统需设计“密码复杂度+登录失败锁定”，如同普通住宅需安装防盗门锁；三级系统需“多因素认证+敏感数据加密”，如同银行金库需指纹+密码+虹膜三重验证+钢板防护，从结构上抵御风险。</li>
</ul>
<h3>三、系统开发“开发编码与组件管理”→ 建筑“材料选型与施工工艺”</h3>
<p>建筑的可靠性取决于“材料质量”与“施工精度”：  </p>
<ul>
<li>材料选型：需选用符合国标的钢筋、水泥（如高层建筑禁用劣质钢材），对应系统开发中“第三方组件管理”——需从官方渠道获取组件（如官方仓库下载框架）、验证组件安全性（如检查哈希值防篡改），避免使用“已淘汰框架”（如同建筑禁用过期水泥）；  </li>
<li>施工工艺：如墙体砌筑需“灰缝均匀、垂直度达标”，对应系统“安全编码规范”——需避免SQL注入（如同墙体避免留缝隙）、过滤恶意输入（如同墙面抹平防渗水）。要求“输入数据合法性检查”，如同建筑施工中需检查每块砖的平整度，避免细节缺陷引发整体隐患。</li>
</ul>
<h3>四、系统开发“测试验收”→ 建筑“竣工验收与质量检测”</h3>
<p>建筑完工后需通过“多维度检测”确保安全达标：  </p>
<ul>
<li>结构检测：如用超声波检测混凝土强度、模拟地震测试抗震能力，对应系统“安全测试”（如渗透测试模拟黑客攻击、漏洞扫描检测组件漏洞）；  </li>
<li>功能验收：如测试电梯运行稳定性、给排水系统密封性，对应系统“功能与性能测试”（如验证权限控制是否生效、高并发下是否崩溃）。例如三级系统需额外开展“源代码审计+商密评估”，如同超高层建筑需额外进行“风洞试验+消防演练”，通过严苛检测排除隐性风险。</li>
</ul>
<h3>五、系统开发“部署上线”→ 建筑“交付使用与初始防护”</h3>
<p>建筑交付时需完成“环境适配”与“初始防护”：  </p>
<ul>
<li>环境适配：如建筑需接入市政水电、调试消防系统，对应系统“部署环境配置”（如政务云环境部署、防火墙规则配置），禁止部署在公有云（如同建筑禁止建在洪水淹没区）；  </li>
<li>初始防护：如建筑交付时启用监控系统、设置门禁权限，对应系统“部署后安全配置”（如关闭不必要端口、启用日志审计）。例如二级系统需“安装防恶意代码软件”，如同住宅交付时配备灭火器；三级系统需“实时入侵检测”，如同商场交付时启用24小时安保巡逻。</li>
</ul>
<h3>六、系统开发“运行维护”→ 建筑“日常运维与翻新加固”</h3>
<p>建筑的长期可靠依赖“持续维护”：  </p>
<ul>
<li>日常巡检：如定期检查屋顶防水、电梯维护，对应系统“安全巡检”（如每月检查服务器CPU/内存、每季度漏洞扫描）；  </li>
<li>翻新加固：如老建筑加装电梯、墙体抗震加固，对应系统“版本更新与漏洞修复”（如及时安装安全补丁、迭代安全策略）；  </li>
<li>应急处置：如建筑火灾时启动喷淋+疏散预案，对应系统“应急响应”（如发现入侵时隔离受影响系统、恢复备份数据）。例如三级系统需“7*24小时监控+异地备份”，如同医院需24小时急诊+备用发电机，确保突发情况（如断电/攻击）下业务不中断。</li>
</ul>
<h3>核心类比逻辑：安全是“底线”，稳定是“结构”，可靠是“长期保障”</h3>
<p>建筑的本质是“在特定环境下，用合理成本实现安全、稳定、可靠的空间功能”，系统开发同理——需在“业务需求”与“安全成本”间平衡（如同建筑需在“居住需求”与“建造成本”间平衡），通过全流程的“设计-选型-施工-检测-运维”，让系统像建筑一样，既能承载业务功能（如同建筑承载居住/办公需求），又能抵御外部风险（如同建筑抵御风雨/盗窃），长期稳定运行（如同建筑使用寿命达50年+）。</p>]]></description>
    <pubDate>Sun, 26 Oct 2025 08:12:02 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=19</guid>
</item>
<item>
    <title>按思维导图逻辑分类的 ES6 保留关键字汇总</title>
    <link>https://www.fsgoa.com/?post=18</link>
    <description><![CDATA[<p>以下是按思维导图逻辑分类的ES6保留关键字汇总，按「功能场景」划分，便于关联记忆：</p>
<h3><strong>一、声明与定义类/变量</strong></h3>
<ul>
<li><strong>类相关</strong>  
<ul>
<li><code>class</code>（定义类）  </li>
<li><code>constructor</code>（类的构造方法）  </li>
<li><code>extends</code>（类继承）  </li>
<li><code>super</code>（访问父类属性/方法）  </li>
</ul></li>
<li><strong>变量声明</strong>  
<ul>
<li><code>let</code>（块级变量）  </li>
<li><code>const</code>（块级常量）  </li>
</ul></li>
</ul>
<h3><strong>二、模块系统</strong></h3>
<ul>
<li><code>import</code>（导入模块）  </li>
<li><code>export</code>（导出模块成员）  </li>
<li><code>default</code>（配合<code>export</code>指定默认导出）  </li>
</ul>
<h3><strong>三、函数与流程控制</strong></h3>
<ul>
<li><strong>生成器函数</strong>  
<ul>
<li><code>function*</code>（定义生成器函数）  </li>
<li><code>yield</code>（生成器中暂停/恢复执行）  </li>
<li><code>yield*</code>（委托给其他可迭代对象）  </li>
</ul></li>
<li><strong>异步函数</strong>（ES2017，基于ES6扩展）  
<ul>
<li><code>async</code>（定义异步函数）  </li>
<li><code>await</code>（等待Promise结果）  </li>
</ul></li>
</ul>
<h3><strong>四、未来预留关键字（暂未启用）</strong></h3>
<ul>
<li>类成员修饰符：<code>public</code>、<code>private</code>、<code>protected</code>  </li>
<li>接口相关：<code>interface</code>、<code>implements</code>  </li>
<li>模块打包：<code>package</code>  </li>
<li>枚举：<code>enum</code>  </li>
</ul>
<h3><strong>五、沿用自ES5及之前的关键字</strong></h3>
<p>（基础语法必备，需结合已有知识记忆）  </p>
<ul>
<li>流程控制：<code>break</code>、<code>case</code>、<code>catch</code>、<code>continue</code>、<code>default</code>、<code>do</code>、<code>else</code>、<code>finally</code>、<code>for</code>、<code>if</code>、<code>return</code>、<code>switch</code>、<code>while</code>  </li>
<li>对象与操作：<code>delete</code>、<code>in</code>、<code>instanceof</code>、<code>new</code>、<code>this</code>、<code>throw</code>、<code>try</code>、<code>typeof</code>、<code>void</code>、<code>with</code>  </li>
<li>函数与变量：<code>function</code>、<code>var</code>、<code>debugger</code>  </li>
</ul>
<h3><strong>记忆技巧</strong></h3>
<ol>
<li><strong>按使用频率</strong>：优先记住常用的（<code>class</code>、<code>let</code>、<code>const</code>、<code>import</code>、<code>export</code>等），再记未来预留的。  </li>
<li><strong>关联场景</strong>：比如看到<code>class</code>就联想到<code>constructor</code>、<code>extends</code>、<code>super</code>，看到<code>import</code>就关联<code>export</code>和<code>default</code>。  </li>
<li><strong>区分新旧</strong>：ES6新增的多与「类、模块、生成器」相关，沿用的多是基础语法关键字。  </li>
</ol>
<p>通过功能场景归类，能快速建立关键字与使用场景的关联，减少记忆负担。</p>]]></description>
    <pubDate>Sun, 19 Oct 2025 13:52:19 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=18</guid>
</item>
<item>
    <title>为何js数组的forEach是value开头，而index是后面的，为何不设为index开头而value在后的原因</title>
    <link>https://www.fsgoa.com/?post=17</link>
    <description><![CDATA[<p>JavaScript 数组的 <code>forEach</code> 方法将 <code>value</code> 放在参数第一位、<code>index</code> 放在第二位，这一设计主要基于以下原因：</p>
<ol>
<li>
<p><strong>使用频率考量</strong>：在大多数迭代场景中，开发者更关注数组元素的值（<code>value</code>）而非其索引（<code>index</code>）。将 <code>value</code> 作为第一个参数可以让常见操作的代码更简洁，无需显式声明不需要的索引参数。</p>
<p>例如，简单遍历值时：</p>
<pre><code class="language-javascript">arr.forEach(value =&gt; console.log(value)); // 简洁直观</code></pre>
</li>
<li>
<p><strong>与其他方法保持一致性</strong>：JavaScript 中许多数组方法（如 <code>map</code>、<code>filter</code>、<code>reduce</code> 的回调函数）都遵循「值在前，索引在后」的参数顺序，形成了统一的设计风格，降低了开发者的学习成本。</p>
</li>
<li>
<p><strong>历史设计延续性</strong>：早期 JavaScript 设计受函数式编程思想影响，强调对数据本身的操作而非位置信息。这种参数顺序延续了函数式语言中「值优先」的传统。</p>
</li>
</ol>
<p>如果需要优先使用索引，可以通过参数位置显式获取：</p>
<pre><code class="language-javascript">arr.forEach((value, index) =&gt; {
  console.log(`索引 ${index} 的值是 ${value}`);
});</code></pre>
<p>这种设计虽然在少数场景（如更关注索引时）略显不便，但整体上符合大多数开发者的使用习惯，保持了 API 的简洁性和一致性。</p>]]></description>
    <pubDate>Sun, 19 Oct 2025 12:52:18 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=17</guid>
</item>
<item>
    <title>pyjwt中，假如修改这个token的荷载中的exp值，再生成荷载，那jwt能否检测到的实验</title>
    <link>https://www.fsgoa.com/?post=16</link>
    <description><![CDATA[<p>JWT（JSON Web Token）的签名机制确保了令牌的完整性和真实性。如果你修改了 JWT 的荷载（payload）中的 <code>exp</code> 值或其他任何字段，然后尝试使用原始的签名，JWT 的验证将失败，因为签名不再匹配修改后的荷载。</p>
<h3>示例：验证修改后的 JWT</h3>
<p>假设你有一个原始的 JWT 令牌：</p>
<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg1MDc0fQ.your_signature_here</code></pre>
<p>如果你修改了荷载中的 <code>exp</code> 值，例如将其改为 <code>1743086137</code>，新的荷载部分将变为：</p>
<pre><code>eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ</code></pre>
<p>如果你尝试将修改后的荷载与原始签名组合成一个新的令牌：</p>
<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ.your_signature_here</code></pre>
<p>这个令牌将无法通过验证，因为签名部分不再匹配荷载部分。</p>
<h3>Python 验证代码</h3>
<p>以下是使用 Python 的 <code>PyJWT</code> 库验证 JWT 的示例代码：</p>
<pre><code class="language-python">import jwt

# JWT 配置
SECRET_KEY = "your-secret-key"  # 替换为你的密钥
ALGORITHM = "HS256"

# 示例：验证 JWT 签名
def verify_jwt(token: str):
    try:
        # 解码并验证 JWT 签名
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.ExpiredSignatureError:
        print("Token has expired")
        return None
    except jwt.InvalidTokenError:
        print("Invalid token")
        return None

# 示例令牌（修改后的）
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ.qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo"

# 验证令牌
decoded_payload = verify_jwt(token)
if decoded_payload:
    print("Decoded payload:", decoded_payload)
else:
    print("Token verification failed")</code></pre>
<h3>输出结果</h3>
<p>运行上述代码后，输出结果为：</p>
<pre><code>Invalid token
Token verification failed</code></pre>
<h3>原因解释</h3>
<ol>
<li>
<p><strong>签名不匹配</strong>：</p>
<ul>
<li>JWT 的签名部分是基于原始的荷载和头部生成的。如果你修改了荷载中的任何字段（如 <code>exp</code>），签名将不再有效。</li>
</ul>
</li>
<li>
<p><strong>验证失败</strong>：</p>
<ul>
<li>在验证过程中，<code>jwt.decode()</code> 方法会重新计算签名并将其与令牌中的签名进行比较。如果两者不匹配，将抛出 <code>InvalidTokenError</code> 异常。</li>
</ul>
</li>
</ol>
<h3>总结</h3>
<p>JWT 的签名机制确保了令牌的完整性和真实性。任何对荷载或头部的修改都会导致签名不匹配，从而在验证时被检测到。这就是为什么即使你修改了 <code>exp</code> 值，JWT 也能检测到并拒绝验证的原因。</p>
<h3>最后的实验结果</h3>
<p>playload为：<br />
{<br />
&quot;user_id&quot;: 123,<br />
&quot;username&quot;: &quot;zhoucl&quot;,<br />
&quot;exp&quot;: 1743086137<br />
}<br />
经过pyjwt生成的token的playload：eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ<br />
完整token：eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ.qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo</p>
<p>仅仅修改playload中exp中的值：<br />
{<br />
&quot;user_id&quot;: 123,<br />
&quot;username&quot;: &quot;zhoucl&quot;,<br />
&quot;exp&quot;: 1743096137 </p>
<p>}<br />
替换中间playload：eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDk2MTM3fQ<br />
但沿用原来的签名：qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo<br />
经过hack后的token：<br />
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDk2MTM3fQ.qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo</p>
<p>pyjwt正常加密hack的playload的token值：<br />
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDk2MTM3fQ.lNzt3YebtF-TpviYvyTK0396V-5hIeNZD9FIB2SR_Ps<br />
签名为：lNzt3YebtF-TpviYvyTK0396V-5hIeNZD9FIB2SR_Ps</p>
<p>总结：playload是否被修改，该算法是比对最后的签名值：<br />
hack playload：eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDk2MTM3fQ<br />
原来  playload：eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ</p>
<p>hack playload签名：lNzt3YebtF-TpviYvyTK0396V-5hIeNZD9FIB2SR_Ps<br />
原来  playload签名：qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo<br />
<a href="http://www.fsgoa.com/content/uploadfile/202503/68031743084593.png"><img src="http://www.fsgoa.com/content/uploadfile/202503/68031743084593.png" alt="" /></a></p>]]></description>
    <pubDate>Thu, 27 Mar 2025 22:07:54 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=16</guid>
</item>
<item>
    <title>用简洁的易懂的语言解析python装饰器的执行流程</title>
    <link>https://www.fsgoa.com/?post=15</link>
    <description><![CDATA[<h3><strong>Python装饰器的执行流程（三步走）</strong></h3>
<hr />
<h4><strong>1. 定义阶段：函数头上贴标签</strong></h4>
<p>当你写 <code>@装饰器</code> 时，相当于告诉 Python：<strong>“把这个函数包装一下”</strong>。<br />
<strong>示例代码：</strong></p>
<pre><code class="language-python">def 装饰器(原函数):       # 装饰器函数（负责包装）
    def 新函数():         # 新函数会替代原函数
        print("装饰器：开始")  
        原函数()          # 调用原函数
        print("装饰器：结束")
    return 新函数         # 返回包装后的新函数

@装饰器                  # 相当于：我的函数 = 装饰器(我的函数)
def 我的函数():
    print("原函数执行")</code></pre>
<hr />
<h4><strong>2. 执行阶段：装饰器立刻生效</strong></h4>
<p><strong>装饰器在代码加载时立即执行</strong>（比如导入模块或运行脚本时），而不是等到调用函数！<br />
<strong>执行流程：</strong></p>
<ol>
<li><strong>调用装饰器函数</strong>：Python 会把 <code>我的函数</code> 作为参数传给 <code>装饰器</code>。</li>
<li><strong>生成新函数</strong>：装饰器返回 <code>新函数</code>，替换原来的 <code>我的函数</code>。<br />
<strong>此时，<code>我的函数</code> 已经变成了 <code>新函数</code>。</strong></li>
</ol>
<hr />
<h4><strong>3. 调用阶段：实际执行的是包装后的函数</strong></h4>
<p>当你调用 <code>我的函数()</code> 时，<strong>实际执行的是 <code>新函数</code></strong>。<br />
<strong>输出结果：</strong></p>
<pre><code>装饰器：开始  
原函数执行  
装饰器：结束</code></pre>
<hr />
<h3><strong>一句话总结流程</strong></h3>
<p><strong>“先包装，再替换”</strong>  </p>
<ol>
<li><strong>定义时</strong>：<code>@装饰器</code> 触发装饰器函数执行，生成新函数。  </li>
<li><strong>调用时</strong>：执行的是被装饰器包裹后的新函数。</li>
</ol>
<hr />
<h3><strong>类比理解：礼物的包装</strong></h3>
<ol>
<li><strong>原函数</strong>：礼物本身  </li>
<li><strong>装饰器</strong>：包装盒和彩带（在礼物外面加一层包装）  </li>
<li><strong>调用函数</strong>：拆开包装盒，最终拿到礼物（原函数逻辑）</li>
</ol>]]></description>
    <pubDate>Wed, 26 Mar 2025 22:19:25 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=15</guid>
</item>
<item>
    <title>python为何不用类的变量而用闭包呢？</title>
    <link>https://www.fsgoa.com/?post=14</link>
    <description><![CDATA[<p>闭包和类都可以用来封装状态，但它们的适用场景和设计思想不同。<strong>闭包更适合轻量级、单一功能的状态封装，而类适合需要组合数据与多个方法的复杂场景</strong>。以下是具体对比和选择依据：</p>
<hr />
<h3><strong>1. 闭包 vs 类的核心区别</strong></h3>
<table>
<thead>
<tr>
<th><strong>特性</strong></th>
<th><strong>闭包</strong></th>
<th><strong>类（实例对象）</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>代码复杂度</strong></td>
<td>轻量级，无需定义类和方法</td>
<td>需要定义类、方法，结构更正式</td>
</tr>
<tr>
<td><strong>状态访问</strong></td>
<td>通过外层变量隐式传递，天然私有</td>
<td>通过 <code>self.变量</code> 显式管理，可设为“伪私有”</td>
</tr>
<tr>
<td><strong>功能扩展性</strong></td>
<td>只能通过外层变量扩展</td>
<td>支持多方法、继承、属性访问器等复杂扩展</td>
</tr>
<tr>
<td><strong>内存占用</strong></td>
<td>通常更小（仅保存必要的变量）</td>
<td>略大（包含类实例的额外元信息）</td>
</tr>
<tr>
<td><strong>适用场景</strong></td>
<td>简单状态封装、工厂函数、装饰器、回调</td>
<td>复杂业务逻辑、多方法协作、需要复用性</td>
</tr>
</tbody>
</table>
<hr />
<h3><strong>2. 何时用闭包？典型场景</strong></h3>
<h4><strong>① 轻量级状态管理</strong></h4>
<p>当只需保存少量状态，且无需多个方法操作时，闭包更简洁。</p>
<p><strong>例子：计数器</strong></p>
<pre><code class="language-python"># 闭包实现
def create_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = create_counter()
print(c(), c())  # 1, 2

# 类实现
class Counter:
    def __init__(self):
        self.count = 0
    def incr(self):
        self.count += 1
        return self.count

c = Counter()
print(c.incr(), c.incr())  # 1, 2</code></pre>
<p><strong>闭包优势</strong>：无需写类，代码更短，变量 <code>count</code> 天然私有（外部无法直接访问）。</p>
<hr />
<h4><strong>② 工厂函数生成定制逻辑</strong></h4>
<p>闭包可以根据参数动态生成不同行为的函数。</p>
<p><strong>例子：根据权限生成查询函数</strong></p>
<pre><code class="language-python"># 闭包实现
def query_factory(role):
    def query(data):
        if role == "admin":
            return f"Secret: {data}"
        return f"Public: {data}"
    return query

user_query = query_factory("user")
admin_query = query_factory("admin")

print(user_query("data1"))  # Public: data1
print(admin_query("data2")) # Secret: data2

# 类实现
class Query:
    def __init__(self, role):
        self.role = role
    def run(self, data):
        if self.role == "admin":
            return f"Secret: {data}"
        return f"Public: {data}"

user_query = Query("user")
admin_query = Query("admin")
print(user_query.run("data1"))  # Public: data1</code></pre>
<p><strong>闭包优势</strong>：直接返回函数，调用时无需 <code>.run()</code>，更符合函数式编程风格。</p>
<hr />
<h4><strong>③ 装饰器（核心场景）</strong></h4>
<p>装饰器本质是闭包，用于增强函数行为。</p>
<p><strong>例子：计时装饰器</strong></p>
<pre><code class="language-python"># 闭包实现
import time

def timer(func):
    def wrapper():
        start = time.time()
        func()
        print(f"Time: {time.time() - start:.2f}s")
    return wrapper

@timer
def my_func():
    time.sleep(1)

my_func()  # 输出执行时间

# 类实现（较少用，但可行）
class Timer:
    def __init__(self, func):
        self.func = func
    def __call__(self):
        start = time.time()
        self.func()
        print(f"Time: {time.time() - start:.2f}s")

@Timer
def my_func():
    time.sleep(1)

my_func()</code></pre>
<p><strong>闭包优势</strong>：代码更简洁，无需定义 <code>__call__</code> 方法。</p>
<hr />
<h3><strong>3. 何时用类？闭包的局限性</strong></h3>
<h4><strong>① 需要多个方法协作</strong></h4>
<p>闭包只能封装一个主函数，而类可以定义多个方法。</p>
<pre><code class="language-python"># 类更合适：银行账户需要存钱、取钱、查询
class BankAccount:
    def __init__(self, balance):
        self.balance = balance
    def deposit(self, amount):
        self.balance += amount
    def withdraw(self, amount):
        if self.balance &gt;= amount:
            self.balance -= amount
    def check(self):
        return self.balance

# 闭包实现会非常笨拙
def create_account(initial):
    balance = initial
    def dispatch(cmd, amount=None):
        nonlocal balance
        if cmd == "deposit":
            balance += amount
        elif cmd == "withdraw":
            if balance &gt;= amount:
                balance -= amount
        elif cmd == "check":
            return balance
    return dispatch

account = create_account(100)
account("deposit", 50)
print(account("check"))  # 150</code></pre>
<p><strong>类的优势</strong>：方法明确，代码可读性更高。</p>
<hr />
<h4><strong>② 需要继承或复用代码</strong></h4>
<p>类支持继承、Mixin 等特性，闭包无法做到。</p>
<pre><code class="language-python">class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "Woof!"

class Cat(Animal):
    def speak(self):
        return "Meow!"</code></pre>
<hr />
<h4><strong>③ 需要持久化复杂状态</strong></h4>
<p>闭包的变量隐藏在作用域内，调试和序列化困难，而类的实例变量更透明。</p>
<pre><code class="language-python"># 类的状态可轻松查看和修改
obj = MyClass()
print(obj.__dict__)  # 查看所有变量

# 闭包的状态对外不可见
closure = create_closure()
print(closure.__closure__[0].cell_contents)  # 可行但晦涩</code></pre>
<hr />
<h3><strong>总结</strong></h3>
<ul>
<li><strong>用闭包</strong>：简单状态封装、函数工厂、装饰器、回调等轻量级场景。</li>
<li><strong>用类</strong>：多方法协作、复杂业务逻辑、需要继承或明确数据结构的场景。</li>
</ul>
<p>闭包和类不是对立的，而是互补的工具。<strong>Python 的函数式特性（闭包）和面向对象特性（类）结合使用，才能写出灵活高效的代码</strong>。例如，装饰器（闭包）可以修饰类方法，而类方法内部也可以使用闭包实现局部逻辑。</p>]]></description>
    <pubDate>Wed, 26 Mar 2025 22:16:16 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=14</guid>
</item>
<item>
    <title>什么是处理依赖项</title>
    <link>https://www.fsgoa.com/?post=13</link>
    <description><![CDATA[<p>在编程和软件开发中，“处理依赖项”（Handling Dependencies）是一个非常重要的概念。它指的是在执行某个操作或运行某个函数之前，先完成某些前置条件或准备工作。这些前置条件或准备工作被称为“依赖项”（Dependencies）。</p>
<h3>依赖项的定义</h3>
<p><strong>依赖项</strong>是指一个函数或模块在运行时所依赖的外部资源、数据或条件。例如：</p>
<ul>
<li>从数据库中获取数据。</li>
<li>验证用户的登录状态。</li>
<li>读取配置文件中的参数。</li>
<li>检查某些条件是否满足。</li>
</ul>
<h3>处理依赖项的目的</h3>
<p>处理依赖项的主要目的是确保在执行主逻辑之前，所有必要的准备工作都已完成。这样可以：</p>
<ol>
<li><strong>简化代码逻辑</strong>：将复杂的准备工作封装起来，主逻辑只需要关注核心功能。</li>
<li><strong>提高复用性</strong>：将通用的准备工作抽象成独立的函数或模块，可以在多个地方复用。</li>
<li><strong>增强可维护性</strong>：依赖项的处理逻辑集中管理，便于修改和维护。</li>
<li><strong>提高安全性</strong>：例如，通过依赖项处理可以确保用户在访问敏感数据之前已经通过身份验证。</li>
</ol>
<h3>示例：处理依赖项</h3>
<p>假设你正在开发一个在线商店的后端服务，其中一个功能是“获取用户订单”。在执行这个功能之前，你需要先验证用户是否已经登录。这里的“验证用户是否登录”就是一个依赖项。</p>
<h4>代码示例</h4>
<p>以下是一个简单的 Python 示例，展示如何处理依赖项：</p>
<pre><code class="language-python"># 模拟数据库中的用户数据
users = {"user1": "password123"}

# 依赖项：验证用户是否登录
def authenticate_user(username: str, password: str):
    if username in users and users[username] == password:
        return True
    else:
        raise ValueError("Invalid username or password")

# 主功能：获取用户订单
def get_user_orders(username: str):
    # 假设这里从数据库中获取订单
    orders = ["Order1", "Order2"]
    return f"Orders for {username}: {orders}"

# 模拟请求
def main():
    try:
        # 处理依赖项：验证用户
        is_authenticated = authenticate_user("user1", "password123")
        if is_authenticated:
            # 执行主功能
            orders = get_user_orders("user1")
            print(orders)
    except ValueError as e:
        print(e)

if __name__ == "__main__":
    main()</code></pre>
<h3>输出结果</h3>
<p>运行这段代码后，输出结果为：</p>
<pre><code>Orders for user1: ['Order1', 'Order2']</code></pre>
<h3>依赖项处理的关键点</h3>
<ol>
<li>
<p><strong>依赖项的封装</strong>：</p>
<ul>
<li>将依赖项的处理逻辑封装成独立的函数或模块，例如 <code>authenticate_user</code>。</li>
<li>这样可以将复杂的准备工作与主逻辑分离，简化代码结构。</li>
</ul>
</li>
<li>
<p><strong>依赖项的调用</strong>：</p>
<ul>
<li>在主逻辑执行之前，先调用依赖项处理函数。</li>
<li>如果依赖项处理失败（例如用户验证失败），可以提前返回错误，避免执行主逻辑。</li>
</ul>
</li>
<li>
<p><strong>依赖项的复用</strong>：</p>
<ul>
<li>依赖项处理函数可以被多个主逻辑复用。例如，<code>authenticate_user</code> 可以被多个需要用户验证的功能调用。</li>
</ul>
</li>
</ol>
<h3>FastAPI 中的依赖项处理</h3>
<p>在 FastAPI 中，<code>Depends()</code> 是一个专门用于处理依赖项的机制。它可以帮助你将依赖项的处理逻辑封装起来，并在路由函数执行之前自动调用这些依赖项。</p>
<h4>FastAPI 示例</h4>
<p>以下是一个 FastAPI 示例，展示如何使用 <code>Depends()</code> 处理依赖项：</p>
<pre><code class="language-python">from fastapi import FastAPI, Depends, HTTPException

app = FastAPI()

# 模拟数据库中的用户数据
users = {"user1": "password123"}

# 依赖项：验证用户是否登录
def authenticate_user(username: str, password: str):
    if username in users and users[username] == password:
        return True
    else:
        raise HTTPException(status_code=401, detail="Invalid username or password")

# 主路由：获取用户订单
@app.get("/orders/")
async def get_user_orders(username: str, password: str, authenticated: bool = Depends(authenticate_user)):
    # 假设这里从数据库中获取订单
    orders = ["Order1", "Order2"]
    return {"username": username, "orders": orders}</code></pre>
<p>在这个 FastAPI 示例中：</p>
<ul>
<li><code>authenticate_user</code> 是一个依赖项处理函数，它验证用户的用户名和密码。</li>
<li>在路由函数 <code>get_user_orders</code> 中，通过 <code>Depends(authenticate_user)</code> 自动调用依赖项处理函数。</li>
<li>如果用户验证失败，FastAPI 会自动返回一个 401 错误，而不会执行主逻辑。</li>
</ul>
<h3>总结</h3>
<p>处理依赖项是确保程序在执行主逻辑之前完成所有必要准备工作的过程。通过将依赖项的处理逻辑封装起来，可以简化代码结构，提高复用性和可维护性。在 FastAPI 中，<code>Depends()</code> 是一个强大的工具，专门用于处理依赖项，使得依赖项的管理更加方便和高效。</p>]]></description>
    <pubDate>Wed, 26 Mar 2025 22:13:46 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=13</guid>
</item>
<item>
    <title>编译安装python且不能与现在的版本冲突的方法</title>
    <link>https://www.fsgoa.com/?post=12</link>
    <description><![CDATA[<p>在Linux系统中，编译安装Python并且避免与现有版本冲突，可以按照以下步骤进行操作：</p>
<h3>1. 安装依赖</h3>
<p>在编译安装Python之前，需要安装一些必要的依赖库。以Ubuntu系统为例，可以使用以下命令安装依赖：</p>
<pre><code class="language-bash">sudo apt-get update
sudo apt-get install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev curl libbz2-dev</code></pre>
<h3>2. 下载Python源码</h3>
<p>从Python官方网站下载所需的Python版本源码。例如，下载Python 3.9.6：</p>
<pre><code class="language-bash">curl -O https://www.python.org/ftp/python/3.9.6/Python-3.9.6.tgz</code></pre>
<h3>3. 解压源码</h3>
<p>将下载的源码包解压：</p>
<pre><code class="language-bash">tar -xzf Python-3.9.6.tgz
cd Python-3.9.6</code></pre>
<h3>4. 配置编译选项</h3>
<p>运行<code>./configure</code>命令来配置编译选项。为了确保安装的Python不会与系统默认的Python版本冲突，可以指定安装路径。例如，安装到<code>/usr/local/python3.9.6</code>目录：</p>
<pre><code class="language-bash">./configure --prefix=/usr/local/python3.9.6 --enable-optimizations</code></pre>
<h3>5. 编译源码</h3>
<p>运行<code>make</code>命令来编译源码：</p>
<pre><code class="language-bash">make</code></pre>
<h3>6. 安装Python</h3>
<p>使用<code>make altinstall</code>命令来安装Python，这样可以避免覆盖系统默认的Python版本：</p>
<pre><code class="language-bash">sudo make altinstall</code></pre>
<h3>7. 验证安装</h3>
<p>安装完成后，可以使用以下命令验证新安装的Python版本：</p>
<pre><code class="language-bash">python3.9.6 --version</code></pre>
<p>通过以上步骤，就可以在不与现有Python版本冲突的情况下，成功编译安装新的Python版本。</p>]]></description>
    <pubDate>Tue, 18 Mar 2025 20:25:22 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=12</guid>
</item>
<item>
    <title>make install与make altinstall的区别</title>
    <link>https://www.fsgoa.com/?post=11</link>
    <description><![CDATA[<p>make install和make altinstall是Linux系统中用于安装编译后软件的两个命令，它们在功能和使用场景上有一些区别：</p>
<h3>make install</h3>
<ul>
<li><strong>功能</strong>：会将编译后的软件安装到系统默认的目录，通常是<code>/usr/local/bin/</code>或<code>/usr/bin/</code>等系统路径下。这些路径在系统环境变量中，因此安装后的软件可以直接在命令行中使用。</li>
<li><strong>适用场景</strong>：适用于安装软件的稳定版本，且希望软件能被系统中所有用户使用的情况。</li>
<li><strong>风险</strong>：如果系统中已经存在同名的软件或命令，可能会覆盖原有的文件，导致系统中已安装的软件无法正常使用。</li>
</ul>
<h3>make altinstall</h3>
<ul>
<li><strong>功能</strong>：会将编译后的软件安装到一个替代的目录，通常是<code>/usr/bin/</code>或<code>/usr/local/</code>下的子目录，且不会覆盖系统中已有的同名软件。它常用于安装软件的不同版本，以避免与系统默认版本冲突。</li>
<li><strong>适用场景</strong>：适用于需要安装软件的多个版本，或者在不修改系统默认配置的情况下安装软件的情况。</li>
<li><strong>风险</strong>：相对较低，因为它不会覆盖系统中已有的文件。</li>
</ul>
<h3>实际应用场景</h3>
<ul>
<li><strong>Python版本升级</strong>：当需要升级Python版本时，使用<code>make altinstall</code>安装新的Python版本，可以避免覆盖系统默认的Python版本，从而不影响系统中依赖旧版本Python的软件。</li>
<li><strong>软件开发与测试</strong>：在开发和测试软件时，可能需要同时使用多个版本的软件。使用<code>make altinstall</code>可以方便地安装和管理不同版本的软件。</li>
</ul>
<p>在实际使用中，需要根据具体需求和软件的特性来选择合适的安装命令，以确保系统的稳定性和软件的正常使用。同时，在安装软件之前，建议仔细阅读软件的安装文档和相关说明，以了解具体的安装步骤和注意事项。</p>]]></description>
    <pubDate>Tue, 18 Mar 2025 20:22:23 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=11</guid>
</item>
<item>
    <title>rc.local的名字由来</title>
    <link>https://www.fsgoa.com/?post=10</link>
    <description><![CDATA[<p><code>/etc/rc.local</code> 是一个在 Linux 系统中用于在系统启动时自动执行本地自定义脚本或命令的文件。它的名字由来可以从以下几个方面理解：</p>
<h3>1. <strong><code>rc</code> 的含义</strong></h3>
<ul>
<li><strong><code>rc</code></strong> 是 &quot;run commands&quot; 的缩写，表示该文件包含在启动时自动执行的命令。在 Unix 和 Linux 系统中，许多配置文件都以 <code>rc</code> 结尾，表示它们是用于配置和初始化的。</li>
</ul>
<h3>2. <strong><code>local</code> 的含义</strong></h3>
<ul>
<li><strong><code>local</code></strong> 表示该文件是用于本地系统的自定义配置。与系统默认的启动脚本不同，<code>/etc/rc.local</code> 允许用户添加自己的自定义命令或脚本，这些命令或脚本在系统启动时执行。</li>
</ul>
<h3>3. <strong>历史背景</strong></h3>
<ul>
<li>在早期的 Unix 系统中，<code>/etc/rc</code> 文件用于存放系统启动时需要执行的命令。随着系统的发展，<code>/etc/rc.local</code> 被引入，用于存放本地系统的自定义启动命令，以便与系统默认的启动脚本区分开来。</li>
</ul>
<h3>4. <strong>现代 Linux 系统中的使用</strong></h3>
<ul>
<li>在现代的 Linux 系统中，<code>/etc/rc.local</code> 仍然被广泛使用，尽管具体的实现方式可能有所不同。在 systemd 系统中，<code>/etc/rc.local</code> 通常需要手动启用，并且可能需要添加 <code>#!/bin/bash</code> 或其他适当的解释器声明。</li>
</ul>
<h3>示例</h3>
<p>以下是一个典型的 <code>/etc/rc.local</code> 文件内容示例：</p>
<pre><code class="language-bash">#!/bin/bash
# 在这里添加你的自定义命令或脚本

# 例如，挂载一个网络文件系统
mount -t nfs 192.168.1.100:/shared /mnt/shared

# 例如，启动一个自定义服务
/etc/init.d/mycustomservice start

# 退出时返回 0
exit 0</code></pre>
<h3>总结</h3>
<p><code>/etc/rc.local</code> 的名字由来是基于 Unix 和 Linux 系统中 <code>rc</code> 文件的命名习惯，表示该文件包含在系统启动时自动执行的命令。<code>local</code> 部分强调了该文件用于本地系统的自定义配置。通过在 <code>/etc/rc.local</code> 中添加自定义命令或脚本，用户可以在系统启动时自动执行特定的任务。</p>]]></description>
    <pubDate>Mon, 17 Mar 2025 22:22:49 +0800</pubDate>
    <dc:creator>qkabcd</dc:creator>
    <guid>https://www.fsgoa.com/?post=10</guid>
</item></channel>
</rss>