惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
TaoSecurity Blog
TaoSecurity Blog
V
Visual Studio Blog
The GitHub Blog
The GitHub Blog
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
The Register - Security
The Register - Security
月光博客
月光博客
M
MIT News - Artificial intelligence
B
Blog RSS Feed
博客园 - 叶小钗
Last Week in AI
Last Week in AI
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
The Blog of Author Tim Ferriss
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Check Point Blog
Attack and Defense Labs
Attack and Defense Labs
The Cloudflare Blog
Cloudbric
Cloudbric
O
OpenAI News
Security Archives - TechRepublic
Security Archives - TechRepublic
Help Net Security
Help Net Security
Google DeepMind News
Google DeepMind News
Stack Overflow Blog
Stack Overflow Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
大猫的无限游戏
大猫的无限游戏
www.infosecurity-magazine.com
www.infosecurity-magazine.com
V2EX - 技术
V2EX - 技术
Google Online Security Blog
Google Online Security Blog
博客园 - Franky
雷峰网
雷峰网
J
Java Code Geeks
L
LINUX DO - 最新话题
T
Tenable Blog
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
T
Tailwind CSS Blog
Spread Privacy
Spread Privacy
H
Heimdal Security Blog
S
Schneier on Security
量子位
N
Netflix TechBlog - Medium
G
Google Developers Blog
T
The Exploit Database - CXSecurity.com
Cyberwarzone
Cyberwarzone
F
Full Disclosure
S
Securelist

BlogFinder

日常漫步 Vol.24 之漫步前山河 - 雅余 周报 #1-聊聊本周的收获 - Edwin's Blog 我的OpenCode必装插件与Skill Write Something 掌中之物未必在掌握之中 · CRIVU PiliNara,一个更顺手的 PiliPlus 分支 「NekoEcho」:做一个必有回响的猫娘主题博客 2026-05 书影音总结 简化博客主题 - 安迪 你要加油呐 我第一次发布 npm 包 拾花小记#45:中考前的二三事 – 小改学习志 黛西花园5月游 #18 枇杷又熟了的五月月报 一些奇奇怪怪的需求?word仿方正书版的几个小操作 - Xiobb's Blog 0419 御温泉之旅 修复了一些bug,网站基本上趋于稳定了 - 新锐博客 又回到四十年前 如何定义成功 迷鹿屋2026已重新上线 科技冰火两重天+一周回顾 ${title} 热度退了,我反而用得更深了-咕咚同学 我到底该不该换个域名? 随身WIFI折腾记 - 安迪 博客撰写体验提升——hexo pro插件 为什么不用相机把屏幕上的接关密码拍下来? 国清寺与天台山 – Ouroboros ★★★★☆《挽救计划》——久违的经济上行感 - Davidの3号基地 删除右键“打开方式”里多余选项 第三周刊_No.53|一切都会被支付两次 安卓APP通话记录与录音上传踩坑记录 - 子舒的博客 天量下跌 inBox 笔记 2.3.8,把工具栏交给了你-咕咚同学 我把小龙虾搬到了微信-咕咚同学 安好 - 响石潭 Compound Engineering Plugin:让每个工程单元都比上一个更容易 MOSS-TTS Family:开源高质量语音与声音生成模型家族深度解析 Crawl4AI:专为 LLM 设计的开源 Web 爬虫与数据抓取工具 Build Your Own X:从零实现你最喜欢的技术——程序员进阶的终极资源清单 Anthropic Skills:用文件夹教 Claude 专业技能的开源框架 1年的去月球(下) - 梅之夏 欢迎回来。 简单讲讲 ASN.1 与 OID DTV - 直播聚合客户端 5.22-5.27 – 不兴江 还没去过鸭川 – 不兴江 张晶晶同学三刷林志颖 关于我 – 不兴江 爱与嫉妒 – 不兴江 港股被持续做空 备案码花了四百块-咕咚同学 一句话生成封面:我给公众号做了4种风格的AI封面生成技能 「官」方認證 再谈费曼学习法 2026-05-28T00:34:11+08:00 2026-05-28T00:28:45+08:00 离谱的英语学习指南:基于AI的英语进阶系统方法论 iii:零集成架构的后端统一运行时 Claude Code Harness:让 Claude Code 工作有迹可循的工程化框架 Heretic:全自动移除大语言模型审查机制的开源工具 MarkItDown:微软开源的万能文档转 Markdown 利器 Harness:让 Claude Code 秒变多智能体协作工厂 这段时间尽折腾AI Agent了,确实极大地提高了效率 近期动态:两个新站点正式上线啦 误判解除!zhouayuan.com 腾讯安全申诉成功 - 周阿源|玩具设计・插画日常・生活随笔 Ralph:让 AI 编码工具自主循环跑完所有 PRD 任务的量产神器 全都违法 – 个人工作记录 关于zhouayuan.com被误判 “含违规信息” 的说明与申诉记录 - 周阿源|玩具设计・插画日常・生活随笔 小米 MiMo v2.5 Pro 白嫖 最大的人间清醒,兜里有钱,但是不花。 夜晚靓歌(12):于文文现场solo - 王志勇的Blog 今日插画:风扬起的倔强 - 周阿源|玩具设计・插画日常・生活随笔 回门习俗 独立网卡 - 忘记了回忆 500亿入股人工智能企业 从命令行到桌面智能体-咕咚同学 第一性原理读书笔记 行者微评论223-加班の守株待兔-博客|政治与时事-风雨行者 ZOZO开源物理接触求解器:GPU加速的可扩展仿真引擎 OpenStock:开源股票市场交易平台技术深度解析 MoneyPrinterTurbo:基于AI的全自动短视频生成工具深度解析 Claude-Mem:为 Claude Code 构建的持久化记忆压缩系统 Twenty:可代码化定制的企业级开源 CRM 平台技术深度解析 2026-05-26T22:59:17+08:00 企业级开源大模型部署平台 GPUStack 实战教程 1年的去月球(上) - 梅之夏 Sevalla - 静态网站托管服务 不用翻墙、不用注册、不用月费,普通人也能用上 Claude Code 装修灯具要注意⚠️ 黄梅天先锋 - 游子微博 公安备案顺利办结,站点备案全部完成 - 周阿源|玩具设计・插画日常・生活随笔 第三次兑换天猫超市卡了宗宗酱-三维狐少儿编程 Don't think, feel. - Rolen's Blog 人这一辈子,到底图个什么 博客迁移 - Edwin's Blog 情感赛道写作模板 再现本轮行情的典型特征 裁员与平常心-咕咚同学 别让“偷懒”,成为隐私泄露的破绽
typing_extensions 有用(一):使用 Self 终结继承时的类型推断灾难 | 阿尔的代码屋
Algieba · 2026-06-17 · via BlogFinder

核心摘要 (TL;DR)

  • 背景:在 Python 3.11 之前(或需兼容低版本时),当类方法返回当前实例(self)或工厂方法返回当前类实例时,如果发生继承,IDE 往往会将子类的返回值错误推断为父类类型。
  • 核心问题:类型退化(Type Degradation),导致链式调用在子类中断,或反序列化对象后丢失子类特有方法的代码补全。
  • 关键解法:使用 typing_extensions(或 Python 3.11+ 的 typing)中的 Self 类型提示,动态绑定返回值到当前调用类的类型。
  • 适用场景:链式调用(Builder 模式)、类工厂方法(如 from_json)、上下文管理器(__enter__)。

问题概览卡片

基本信息

  • 应用场景:编写需要被继承的基础类库、SDK 构建器或 ORM 框架,且涉及方法返回实例本身。
  • 技术栈:Python 3.8+, typing_extensions (或 Python 3.11+ 原生 typing)
  • 核心痛点:IDE 代码补全失效、类型检查工具(如 Mypy)报属性不存在错误。

错误现象复现

原始代码(痛点展示):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class BaseBuilder:
def set_name(self, name: str) -> "BaseBuilder":
self.name = name
return self

class AgentBuilder(BaseBuilder):
def set_model(self, model: str) -> "AgentBuilder":
self.model = model
return self


builder = AgentBuilder()


builder.set_name("Jarvis").set_model("gpt-4o")

1. 现象描述与现场还原

初始尝试:使用泛型(TypeVar)的局限

Self 出现之前,Python 社区为了解决这个问题,通常需要祭出非常繁琐的泛型(Generics)操作。

1
2
3
4
5
6
7
8
from typing import TypeVar

T = TypeVar('T', bound='BaseBuilder')

class BaseBuilder:
def set_name(self: T, name: str) -> T:
self.name = name
return self

这种写法的局限性:

  • 可读性极差:到处都是 T,对新手极其不友好。
  • 心智负担重:需要为每一个返回 self 的方法显式声明泛型变量。
  • 类方法支持差:在 @classmethod 中使用泛型处理返回类型更加复杂。

2. 根本原因分析

Python 是一种动态语言,但类型提示(Type Hinting)是静态的。

当我们在父类 BaseBuilderset_name 方法上标注 -> "BaseBuilder" 时,我们是在向静态分析工具(Mypy/Pyright)签下一份“死契约”:无论谁调用这个方法,它永远只返回 BaseBuilder

然而,在运行时的真实世界里,如果是 AgentBuilder 继承并调用了这个方法,return self 实际返回的内存对象是一个 AgentBuilder 的实例。

静态契约(父类)运行期真相(子类) 产生了不可调和的矛盾。这就导致了所谓的“类型退化”——IDE 只能遵守那份死契约,从而剥夺了你继续调用子类方法的权利。


PEP 673 引入了 Self 类型。它的核心逻辑是:将返回类型动态绑定到当前实际调用的类(即 self 参数的隐式类型)上。

步骤一:引入依赖

如果你的项目需要兼容 Python 3.8 - 3.10:

1
pip install typing_extensions

步骤二:改造三大经典场景

场景一:拯救链式调用 (Builder 模式)

将死板的父类名替换为 Self,链式调用瞬间丝滑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

from typing_extensions import Self


class BaseBuilder:
def set_name(self, name: str) -> Self:
self.name = name
return self

class AgentBuilder(BaseBuilder):
def set_model(self, model: str) -> Self:
self.model = model
return self



agent = AgentBuilder().set_name("Jarvis").set_model("gpt-4o")

场景二:类工厂方法 (Factory Class Methods)

在 ORM 实体类或反序列化场景中,子类复用父类的解析逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from typing_extensions import Self
import json

class BaseModel:
@classmethod
def from_json(cls, json_str: str) -> Self:
data = json.loads(json_str)
return cls(**data)

class User(BaseModel):
def __init__(self, name: str):
self.name = name

def say_hello(self):
print(f"Hello, {self.name}")


user = User.from_json('{"name": "Alice"}')
user.say_hello()

场景三:规范上下文管理器 (Context Managers)

重写 __enter__ 方法时的最佳实践。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from typing_extensions import Self

class DatabaseSession:
def __init__(self, db_url: str):
self.db_url = db_url

def __enter__(self) -> Self:

return self

def __exit__(self, exc_type, exc_val, exc_tb):

pass

def execute(self, sql: str):
pass


with DatabaseSession("postgresql://...") as session:
session.execute("SELECT 1")

4. 预防与建议

  • 全员标配:在团队项目中,强制要求所有 return self 的实例方法和返回当前类的 @classmethod 都使用 Self 进行类型标注。
  • 平滑升级:虽然 Python 3.11 已经原生支持 Self,但在实际工业项目中,为了兼容旧版本或第三方库的环境,从 typing_extensions 导入依然是最稳妥的做法。该库在较新的 Python 版本下会自动回退(fallback)到原生实现,没有任何性能损耗。
  • 避免滥用:只在方法切实返回调用者自身调用类的新实例时使用。如果一个方法返回的是另一个完全不同的类的实例,请老老实实写具体的类名。

5. 最终成果

场景痛点表现解决方案状态
Builder 继承子类调用父类方法后,无法继续链式调用子类方法方法返回标注为 -> Self✅ IDE 完美补全
反序列化工厂Child.from_json() 返回的类型是 Base@classmethod 返回标注为 -> Self✅ 类型精准下推
Context Managerwith 语句的 as 变量无类型提示__enter__ 方法返回标注为 -> Self✅ 规范严谨

下一篇预告:在 typing_extensions 有用工具系列的第二篇中,我们将探讨 @override,看看它是如何在重构代码时充当“防呆神器”的。