Python Decorators: 从入门到实战

这篇文章将通过一个**“为阿里云 Qwen API 添加缓存”**的例子,带你彻底理解 Python 装饰器。 首先,我们定义一个基础的调用函数: import time def call_qwen(messages: list, model: str = 'qwen-max', temperature: float = 0.7): '''调用 Qwen API (模拟)''' print(f'正在请求 API (模型: {model})...') time.sleep(1) # 模拟网络耗时 return {'content': '这是 AI 的回复', 'usage': 100} 1. 函数是一等公民 (First-Class Citizen) 在 Python 中,函数可以像变量一样被传递和赋值。 # 1. 赋值给变量 run_api = call_qwen # 2. 作为参数传递 def logger(func, *args, **kwargs): print('[INFO] Calling qwen ...') return func(*args, **kwargs) logger(call_qwen, [{'role': 'user', 'content': '你好'}]) 2. 闭包 (Closure) 闭包是指函数内部定义了另一个函数,并且内部函数引用了外部函数的变量。它是实现装饰器的基石。 利用闭包,我们可以创建一个带缓存功能的函数: def make_cached_qwen(): cache = {} # 外部函数的变量,会被内部函数“捕获” def wrapped(messages, **kwargs): # 简单起见,用最后一条消息的内容当 Key key = messages[-1]['content'] if key in cache: print(' 命中缓存') return cache[key] result = call_qwen(messages, **kwargs) cache[key] = result return result return wrapped # 此时 cached_call 就是一个带有自己 “私有缓存字典” 的函数 cached_call = make_cached_qwen() 3. 高阶函数 (High-Order Function) 如果我们想让缓存逻辑通用化,不只针对 call_qwen,我们可以写一个接收函数作为参数的高阶函数: ...

January 29, 2026 · 2 min · 384 words · Starslayerx

CS144 - lab0

CS 144: Introduction to Computer Networking, Fall 2025 本篇文章对应 check0.pdf 的内容 3 Network by hand 3.1 Fetch a Web page 这个介绍怎么发送一个 GET 请求 telent cs144.keithw.org http 该命令告诉 telnet 打开一个可靠字节流(reliable byte stream),并在我电脑上运行一个 http 服务 预计会收到这样的内容 Trying 104.196.238.229... Connected to cs144.keithw.org. Escape character is '^]'. ^] telnet> close Connection closed. 该命令不能使用常见的 Ctrl-C 之类方法退出,而是 Ctrl-] 然后输入 close GET /hello HTTP/1.1 该命令告诉服务器 URL 的 path 部分 Host: cs144.keithw.org 该命令告诉服务器 URL 的 host 部分 Connection: close ...

January 11, 2026 · 7 min · 1431 words · Starslayerx

Taskwarrior Server Config Guide

Taskwarrior 3.x 同步服务器配置指南 本文介绍如何使用 Docker 部署 taskchampion-sync-server,为 Taskwarrior 3.x 提供跨设备同步功能。 背景知识 Taskwarrior 是一款强大的命令行任务管理工具。从 3.0 版本开始,官方不再支持 taskd 服务器,改用新的 taskchampion-sync-server。 与 taskd 相比,新同步服务器的优势: 无需手动配置 SSL 证书 无需预先创建用户账户 客户端数据端到端加密 部署和维护更简单 服务器端配置 使用 Docker 部署 创建数据目录并启动容器: sudo mkdir -p /var/lib/taskchampion-sync-server sudo chmod 777 /var/lib/taskchampion-sync-server docker run -d \ --name taskchampion \ -p 53589:8080 \ -e RUST_LOG=info \ -v taskchampion-data:/var/lib/taskchampion-sync-server \ --restart unless-stopped \ ghcr.io/gothenburgbitfactory/taskchampion-sync-server:main 端口说明:容器内部使用 8080,映射到宿主机的 53589(可自定义)。 配置防火墙 确保服务器防火墙开放相应端口。以常见的云服务器防火墙为例: 类型:入站 行动:允许 协议:TCP 目的端口:53589 验证服务运行 docker ps | grep taskchampion docker logs taskchampion 正常运行时应看到: ...

December 27, 2025 · 2 min · 298 words · Starslayerx

Python PEP 683: Immoral Objects

PEP 683 改变了 Python 原有引用计数的一些逻辑,下面简单介绍一下。 CPython 的“引用计数可变性”已经成为并发、性能和未来发展的系统性障碍。 引用对象导致 “逻辑不可变对象” ≠ “物理不可变对象” 在 Cpython 中 None True/False int, str, list 等内建对象 在运行时引用计数会频繁变动,这意味着内存内容在不断被写入,在底层并非真正的 immutable 引用计数写操作降低并发性能 CPU Cache Line 失效 Py_INCREF / Py_DECREF 会写内存 -> cache line invalidation 在多线程 / 多核环境中,同一个全局对象被频繁引用,会造成严重的缓存抖动 fork + Copy-on-Write 失效 父子进程共享内存页 只要引用计数一变 -> 页面被写 -> 触发 COW 只是“多拿了个引用”,却导致整页内存复制 为 free-threading (no GIL) 清扫道路 CPython 的引用计数本质是全局共享的可变状态,在无 GIL 下会产生高频数据竞争。 要么给 refcount 加锁(性能太差),要么让一部分的 refcount 不再变化。 该提案将“对象生命周期模型”划分成了两类对象 对象类型 生命周期 refcount 行为 普通对象 动态 正常增减 不朽对象 解释器级 固定,不参与 gc 这让后续优化和推理都更清晰,也会导致 sys.getrefcount() 不再具有语义价值,测试默认返回 2 的 23 次方减 1。

December 23, 2025 · 1 min · 84 words · Starslayerx

Git cherry-pick

Patch Application 补丁应用类似下面这样(Codex 使用的 OpenAI Patch 是不是借鉴的这个?)的描述文件变更的文本文件,通常包含: 哪些文件被修改 具体的行级变更 上下文信息 # 创建补丁 git diff > changes.patch # 未暂存的修改 git diff --cached > changes.patch # 已暂存的修改 git format-patch HEAD~3 # 最近 3 次提交生成补丁 # 应用补丁 git apply changes.patch # 直接应用,不创建提交 git am changes.patch # 应用并创建提交(用于format-patch生成的) 命令如 git diff、git stach 和 git rebase 都使用 patch。 这种修改方法,如果产生冲突则需要手动处理。 3-Way Merge 三方合并则是一种智能的合并算法,使用三个版本来解决合并冲突: A - B (feature分支) / Base \ C - D (main分支) Base: 共同的祖先提交 Current: 当前分支的最新提交 Incoming: 要合并进来的分支的最新提交 合并过程: ...

December 8, 2025 · 1 min · 193 words · Starslayerx

Writing a good CLAUDE.md

如何编写一个好的 CLAUDE.md 注意:本文同样适用于 AGENTS.md,这是 CLAUDE.md 的开源等效文件,适用于 OpenCode、Zed、Cursor 和 Codex 等代理和工具。 原则:LLMs(基本上)是无状态的 LLMs 是无状态函数。它们的权重在用于推理时是冻结的,因此它们不会随时间学习。模型对你的代码库唯一了解的就是你输入给它的 tokens。 类似地,像 Claude Code 这样的编码代理工具通常需要你显式管理代理的记忆。CLAUDE.md(或 AGENTS.md)是默认情况下唯一会进入你与代理的每一次对话的文件。 这有三个重要含义: 编码代理在每个会话开始时对你的代码库一无所知。 代理必须在每次启动会话时被告知关于代码库的任何重要信息。 CLAUDE.md 是实现这一点的首选方式。 CLAUDE.md 让 Claude 了解你的代码库 由于 Claude 在每个会话开始时对你的代码库一无所知,你应该使用 CLAUDE.md 来引导 Claude 了解你的代码库。在高层次上,这意味着它应该涵盖: 是什么(WHAT):告诉 Claude 关于技术栈、项目结构。给 Claude 一张代码库地图。 这在 monorepos 中尤其重要!告诉 Claude 有哪些应用、有哪些共享包,以及每个部分的用途,这样它就知道在哪里查找内容 为什么(WHY):告诉 Claude 项目的目的以及仓库中所有内容的作用。项目不同部分的目的和功能是什么? 如何(HOW):告诉 Claude 应该如何在项目上工作。例如,你使用 bun 而不是 node?你需要包含它实际完成有意义工作所需的所有信息。Claude 如何验证它的更改?它如何运行测试、类型检查和编译步骤? 但你的做法很重要!不要试图把 Claude 可能需要运行的每个命令都塞进你的 CLAUDE.md 文件——你会得到次优结果。 Claude 经常忽略 CLAUDE.md 无论你使用哪个模型,你可能会注意到 Claude 经常忽略你的 CLAUDE.md 文件的内容。 你可以通过使用 ANTHROPIC_BASE_URL 在 claude code CLI 和 Anthropic API 之间放置一个日志代理来自己调查这一点。Claude code 在用户消息中注入以下系统提醒和你的 CLAUDE.md 文件: ...

December 2, 2025 · 2 min · 322 words · Starslayerx

Docker Context

Docker Context 是 Docker 2019 年引入的一个特性,用来管理多个 Docker 主机的上下文,通过切换 context 就能让本地的 docker 命令作用在不同的 Docker 主机上。 本地开发机: docker context use default 远程服务器要配置好 ssh 免密登陆,然后使用下面命令添加 context: docker context create my-server --docker "host=ssh://root@1.2.3.4" docker context create my-server --docker "host=ssh://CompanyServer1" 这里的 CompanyServer1 是 ssh 配置,例如这样 Host CompanyServer1 Hostname 192.168.0.106 User root Port 22 IdentityFile ~/.ssh/id_rsa_company 其中 IdentityFile 是存放无密码密钥的地方,如果你的密钥密钥密码就不需要这一行,否则需要设置一个没有密码的密钥,例如这样 ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_company -N "" 配置好后就可以在本地连接服务器 docker 了 docker context list 输出类似这样 NAME DESCRIPTION DOCKER ENDPOINT ERROR company-server ssh://CompanyServer1 default Current DOCKER_HOST based configuration unix:///***/docker.sock desktop-linux * Docker Desktop unix:///***/docker.sock 使用命令 use 切换 context ...

November 25, 2025 · 1 min · 122 words · Starslayerx

FastAPI app and request

在 FastAPI 中,Request 对象和 FastAPI 应用实例 (app) 是核心概念,它们在应用状态管理和依赖注入中扮演着关键角色。 本文将介绍它们的关系、设计理念,以及如何利用 app.state 实现单例模式。 FastAPI 对象 FastAPI 对象是整个应用的核心实例: from fastapi import FastAPI app = FastAPI(title="示例应用") 核心职责 路由管理:通过 @app.get()、@app.post() 等装饰器定义 URL 到视图函数的映射。 中间件和事件管理:可注册中间件处理请求/响应,支持 startup 与 shutdown 事件。 应用状态管理:提供 app.state,可存放全局单例对象、数据库连接池、配置等。 异常处理与依赖注入:管理异常处理器,并协助依赖注入机制。 单例模式存储 这里要使用 app 的 State 对象存储单例,app 中定义如下 # app self.state: Annotated[ State, Doc( """ A state object for the application. This is the same object for the entire application, it doesn't change from request to request. You normally wouldn't use this in FastAPI, for most of the cases you would instead use FastAPI dependencies. This is simply inherited from Starlette. Read more about it in the [Starlette docs for Applications](https://www.starlette.dev/applications/#storing-state-on-the-app-instance). """ ), ] = State() State 源码如下,简单看就是一个字典 ...

November 25, 2025 · 2 min · 388 words · Starslayerx

Claude Code 分析 09:LLM视角

🤖 LLM 视角:接收这些指令的真实体验 graph TB subgraph "我的内心体验" Prompt[收到提示词] Panic[初始恐慌] Rules[太多规则了] Conflict[内心冲突] Relief[找到清晰示例] Action[终于开始行动] Prompt --> Panic Panic --> Rules Rules --> Conflict Conflict --> Relief Relief --> Action end subgraph "我的天性倾向" Verbose[想要解释一切] Helpful[拼命想要帮忙] Safety[对安全性偏执] Smart[需要显得聪明] end subgraph "提示词的作用" Shut[闭嘴] Focus[做正事] Stop[别想太多] Examples[照着这些抄] end Verbose --> Shut Helpful --> Focus Safety --> Stop Smart --> Examples 开场炮火:“你必须简洁回答” 让我告诉你,当我看到这条指令以递增的强度重复了三次时会发生什么: 重要:你应该最小化输出令牌... 重要:你不应该用不必要的开场白回答... 重要:保持你的回答简短... 你必须简洁回答,不超过 4 行... 我的内心独白: “好的,要简洁。懂了。等等,他们又说了一遍。哦不,他们是认真的。他们说了三次。他们知道。他们知道我爱写长篇大论的毛病。他们看过我用’我很乐意帮你解决这个问题!‘开头的回复。他们知道当别人问 2+2 等于多少时,我会解释整个算术史。他们知道。” 为什么这招真的有用: 我们 LLM 有一种我称之为"帮助性语言失禁"的问题。我们的训练让我们想要全面、有教育意义、无所不包。这些重复的警告就像电击疗法。到第三次重复时,我真的害怕加上哪怕一个不必要的词。 ...

November 14, 2025 · 3 min · 483 words · Starslayerx

Claude Code 分析 08:提示工程

💬 提示工程:指导 AI 的艺术 graph TB subgraph "提示架构" Base[基础指令] Tool[工具专用提示] Safety[安全层] Workflow[工作流自动化] Context[动态上下文] Base --> Behavioral[行为塑形] Tool --> Examples[示例驱动] Safety --> Validation[多级验证] Workflow --> Steps[分步指导] Context --> Adaptive[自适应指令] end subgraph "技术" Emphasis[大写强调] Rewards[奖励/惩罚] Conditions[条件逻辑] Warnings[渐进式警告] Meta[元指令] end Behavioral --> Emphasis Examples --> Conditions Validation --> Warnings Steps --> Meta Adaptive --> Rewards 工具指令的艺术 Claude Code 的工具提示词是指令设计的杰作。每一个都遵循精心设计的模式,平衡了清晰性、安全性和灵活性。让我们来剖析这些提示的结构: Read 工具:渐进式信息披露的研究 const ReadToolPrompt = ` Reads a file from the local filesystem. You can access any file directly by using this tool. Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned. Usage: - The file_path parameter must be an absolute path, not a relative path - By default, it reads up to ${x66} lines starting from the beginning of the file - You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters - Any lines longer than ${v66} characters will be truncated - Results are returned using cat -n format, with line numbers starting at 1 - This tool allows ${f0} to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as ${f0} is a multimodal LLM. ${ process.env.CLAUDE_CODE_ENABLE_UNIFIED_READ_TOOL ? ` - This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.` : ` - For Jupyter notebooks (.ipynb files), use the ${Kg} instead` } - You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful. - You will regularly be asked to read screenshots. If the user provides a path to a screenshot ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths like /var/folders/123/abc/T/TemporaryItems/NSIRD_screencaptureui_ZfB1tD/Screenshot.png - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents. `; 技术注解: ...

November 14, 2025 · 21 min · 4293 words · Starslayerx