Python Tricks Part 3: Program Structure and Control Flow

Exceptions 异常 exceptions 具有一些标准属性,这些属性在需要针对错误执行进一步操作的代码中可能非常有用。 e.args 这是引发异常时提供的元组,在大多数情况下,这是一个包含描述错误字符串的单元元素元组。 对于 OSError 异常,其值是一个包含整数错误码、字符串错误消息,以及可选文件名的 2 元组或 3 元组。 e.__cause__ 如果该异常是在处理另一个异常时有意引起的 raise ... from ...,Python 会将这两个异常链接起来,形成异常链。 e.__context__ 如果异常是处理异常时无意间导致的,则会产生 e.__context__。 e.__traceback__ 与异常相关联的堆栈回溯对象。 用于存储异常值的变量仅在相关的 except 块内部可以访问,一但控制论离开该块,该变量将变为未定义。 try: int('N/A') except ValueError as e: print('Failed:', e) print(e) # Fails -> NameError. 'e' not defined 多异常处理块通过多个异常子句指定: try: # do something except TypeError as e: # Handle Type error except ValueError as e: # Handle Value error 当然也可以在单个子句中处理多个异常类型 try: # do something except (TypeError, ValueError) as e: # Handle Type or Value error 可以使用 pass 忽略报错 ...

December 17, 2025 · 7 min · 1335 words · Starslayerx

Python Tricks Part 2: Operators, Expressions and Data Manipulation

Literals 整数 04 0b101010 # Binary 二进制 0o52 # Octal 八进制 0x2a # Hexadecimal 十六进制 浮点数,内部使用 IEEE 754 双精度存储 4.2 42. 4.2e+2 # 科学记数法 4.2E2 -4.2e-2 数字类型字面量还可以使用 _ 来方便阅读 123_456_789 Truth Values true: 非0数字、任何非空的字符串,列表,元组或字典 false: 0、None、空列表,元组或字典 Operations Involving Iterables 任何可迭代对象都可以展开,如 list, tuple and set,都通过星号(*)。 items = [1, 2, 3] a = [10, *items, 1] # [10, 1, 2, 3, 1] b = (*items, 10, *items) # [1, 2, 3, 10, 1, 2, 3] c = {10, 11, *items} # {10, 11, 1, 2, 3} 在上面例子中,item 简单的被粘贴到 list, tuple, set 中,就和手动输入进去一样。 有时候这种展开 expansion 被称为“展开操作符” splatting。 ...

December 16, 2025 · 2 min · 328 words · Starslayerx

Python Tricks Part 1: Basis

这篇文章总结一些平时容易被忽略的 Python 知识 Primitives, Variables and Expressions print(f"{year:>3d} {principal:0.2f}") >3d 指至少 3 位十进制数,右对齐 0.2f 指精度为 2 位的浮点数 Arithmetic Operators round(x, [n]): 该函数采用 Banker’s Rounding 银行家舍入法,也叫 四舍六入五成双,当要舍弃的数字正好是 5 时 前一位是偶数 → 向下舍去(向偶数靠拢) 如果前一位是奇数 → 向上进位(向偶数靠拢) 这样做的目的是减少舍入误差的累积,在统计学和金融计算中更为公平。 # 常规四舍五入(Python实际行为是银行家舍入) print(round(1.5)) # 2 (1是奇数,5进位) print(round(2.5)) # 2 (2是偶数,5舍去) print(round(3.5)) # 4 (3是奇数,5进位) print(round(4.5)) # 4 (4是偶数,5舍去) # 更复杂的例子 print(round(1.25, 1)) # 1.2 (2是偶数,5舍去) print(round(1.35, 1)) # 1.4 (3是奇数,5进位) print(round(1.251, 1)) # 1.3 (因为后面还有1,不是正好5,正常进位) 银行家舍入法是 IEEE 754 标准推荐的方式,Python、R、NumPy 等都采用这种舍入方式,能有效减少大量数据计算时的统计偏差。 Python 二进制运算符会将整数视为 2’s complement binary representation 二进制补码,并且符号位会在左侧无限扩展。 此外,Python 不会截断二进制,也不会溢出。 ...

December 15, 2025 · 4 min · 662 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

Python asyncio 03: A first asyncio application

Working with blocking sockets socket 是在网络中读取和写入数据的一种方式。 可以将 socket 看成一个邮件,将信封放到里面后运送到接收者的地址。 下面使用 Python 的内置 socket 模块来创建一个简单的 server import socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 这里,给 socket 函数指定了两个参数,第一个是 socket.AF_INET,这个告诉我们要与什么类型的地址进行交互,在这个例子中是 hostname 和 phonenumber。 第二个是 socket.SO_REUSEADDR,这个参数是说我们使用 TCP 协议进行交互。 然后使用 socket.setsockopt 方法将 socket.SOL_SOCKET 标志设置为 1。这将允许在关闭和快速重启应用,避免 address already in use 这类错误,如果不这样做将会消耗操作系统一段时间来解除与 port 的绑定。 使用 socket.socket 创建 socket 后,并不能开始沟通,因为还没有将其绑定到任何地址上面。 在本例中,将使用电脑本地地址 127.0.0.1 和任意 port 8000 server_address = ('127.0.0.1', 8000) server_socket.bind(server_address) 这里将地址设置为 127.0.0.1:8000,这意味着 client 将能够使用该地址向服务器发送数据,如果要向 client 发送数据,也会看到该地址为来源地址。 接下来,在套接字上调用 listen 方法,主动监听来自客户端的连接请求。 随后,通过调用 accept 方法等待连接建立。 该方法会保持阻塞状态直至接收到连接请求,当连接成功时,将返回一个连接对象及客户端地址。 这个连接对象本质上是一个新的套接字,可以用于与客户端进行双向数据通信 server_socket.listen() connection, client_address = server_socket.accept() 有了这些组件,我们便掌握了创建基于套接字的服务器应用所需的所有基础模块。 该应用将等待连接,并在建立连接后打印提示信息。 ...

December 1, 2025 · 10 min · 1975 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

Python Asyncio 02: Asyncio Basics Part 2

Tasks, coroutines, furtures, and awaitables Coroutines 和 tasks 都是 await 表达式,那他们的相同线程是哪个? 下面介绍 future 也被称作 awaitable,理解 futures 是理解 asyncio 内部工作的重点。 Introducing futures Future 代表一个尚未完成的异步操作的最终结果。 from asyncio import Future my_future = Future() print(f"Is my_future done? {my_future.done()}") my_future.set_result(42) print(f"Is my_future done? {my_future.done()}") print(f"What is the result of my_future? {my_future.result()}") 输出为 Is my_future done? False Is my_future done? True What is the result of my_future? 42 使用构造器 Future 来创建 future,这时 future 没有值,因此调用 done 结果是 False。 然后使用 set_result 设置值,这将 future 标记为 done。 相似的,如果想要在 future 中设置异常,使用 set_exception 方法。 ...

November 21, 2025 · 5 min · 1049 words · Starslayerx

Python Asyncio 02: Asyncio Basics Part 1

Introducing coroutines 创建一个协程 coroutine 而不是创建一个函数类型,使用 async def 关键字,而不是 def: async def coroutine_add_one(number: int) -> int: return number + 1 def add_one(number: int) -> int: return number + 1 function_result = add_one(1) coroutine_result = coroutine_add_one(1) print(f"Function result is {function_result} and the type is {type(function_result)}") print(f"Coroutine result is {coroutine_result} and the type is {type(coroutine_result)}") 输出如下 Function result is 2 and the type is <class 'int'> Coroutine result is <coroutine object coroutine_add_one at 0x103000a00> and the type is <class 'coroutine'> 可以看到,协程返回的不是值,而是一个协程对象。 这里协程并没有执行,而是创建了一个协程对象可在之后运行,要运行一个协程则必须显式地在一个事件循环中运行它。 在 Python 3.7 之后的版本,必须创建事件循环来运行它。 asyncio 库添加了多个函数,抽象了事件循环的管理,例如 asyncio.run(),可以使用它来运行协程: ...

November 20, 2025 · 3 min · 637 words · Starslayerx