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

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
IT之家
IT之家
S
SegmentFault 最新的问题
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
J
Java Code Geeks
博客园 - 聂微东
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
The Cloudflare Blog
博客园_首页
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 【当耐特】
腾讯CDC
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
宝玉的分享
宝玉的分享
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
月光博客
月光博客
NISL@THU
NISL@THU
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
Blog — PlanetScale
Blog — PlanetScale
aimingoo的专栏
aimingoo的专栏
L
LINUX DO - 热门话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Fortinet All Blogs
博客园 - Franky
L
Lohrmann on Cybersecurity
S
Secure Thoughts
量子位
V
Vulnerabilities – Threatpost
Last Week in AI
Last Week in AI
博客园 - 叶小钗
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LINUX DO - 最新话题
I
InfoQ
C
CERT Recently Published Vulnerability Notes
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Proofpoint News Feed
G
GRAHAM CLULEY
Cisco Talos Blog
Cisco Talos Blog

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 情感赛道写作模板 再现本轮行情的典型特征 裁员与平常心-咕咚同学 别让“偷懒”,成为隐私泄露的破绽 片刻 - Jdeal | Life is like a Design.
typing_extensions 有用(四):使用 TypeIs 替代危险的 cast,做最严谨的类型收窄 | 阿尔的代码屋
Algieba · 2026-06-20 · via BlogFinder

核心摘要 (TL;DR)

  • 背景:当你从网络请求或 json.loads() 拿到一个类型为 Any 的数据时,IDE 会失去所有代码补全能力。
  • 核心问题:Python 原生的 isinstance() 无法校验带泛型的复杂类型(如 list[str] 或自定义的字典列表),强行使用 cast() 又会掩盖运行时的真实 Bug。
  • 关键解法:编写自定义的校验函数,并将返回值标注为 TypeIs[T]。这不仅能执行运行时的逻辑校验,还能在静态检查期改变 IDE 对该变量的类型认知。
  • 新旧对比TypeIs 是旧版 TypeGuard 的完美替代品,它能同时在 ifelse 分支中实现精确的类型收窄。

问题概览卡片

基本信息

  • 应用场景:解析外部不可控的 JSON 数据、验证多态函数中传入的复杂参数结构。
  • 技术栈:Python 3.13+ (原生) 或 typing_extensions
  • 核心痛点isinstance 不支持泛型,类型检查器对外部数据束手无策。

案发现场:让人进退两难的 Any

假设我们正在开发一个 Agent,需要解析外部 API 返回的一段 JSON 数据,我们期望它是一个字符串列表 list[str]

原始代码(痛点展示):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import json
from typing import cast, Any


data: Any = json.loads('["apple", "banana"]')







fruits = cast(list[str], data)
for f in fruits:
print(f.upper())

为了解决这个问题,我们需要写一个普通的 Python 函数,专门用来判断变量是不是 list[str]
但普通的函数返回 bool,IDE 拿到 True 之后依然不知道变量是什么类型。

魔法就在于把返回类型改成 TypeIs[list[str]]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from typing import Any
from typing_extensions import TypeIs




def is_str_list(val: Any) -> TypeIs[list[str]]:

if not isinstance(val, list):
return False
return all(isinstance(x, str) for x in val)

def process_api_response(data: Any):
if is_str_list(data):



for item in data:
print(item.upper())
else:

print("API 返回了非法的数据格式")

2. 深度拷问:为什么不用以前的 TypeGuard

如果你一直关注 Python 的类型生态,你可能会说:“这个功能早在 Python 3.10 里的 TypeGuard 不就有了吗?”

这是一个极其深度的进阶知识点:TypeIs 是为了填补 TypeGuard 的致命缺陷而诞生的(PEP 742 替代 PEP 647)。

TypeGuard 的缺陷(单向收窄)

如果你把上面的返回值改成 TypeGuard[list[str]]

  • 当返回 True 时:IDE 知道它是 list[str]。(这没问题)
  • 当返回 False:IDE 认为“它可能不是 list[str],但我也不知道它到底是什么”,所以 IDE 不会排除原始类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from typing import Union
from typing_extensions import TypeGuard, TypeIs

def old_is_int(val: Union[int, str]) -> TypeGuard[int]:
return isinstance(val, int)

def new_is_int(val: Union[int, str]) -> TypeIs[int]:
return isinstance(val, int)

def test_types(data: Union[int, str]):
if old_is_int(data):

pass
else:

pass

if new_is_int(data):

pass
else:

pass

简而言之:TypeIs 的行为完全等价于 Python 原生的 isinstance(),它能够实现“非此即彼”的双向类型收窄!


3. 经典工业级实战场景

在 LangGraph 或复杂的业务流中,我们经常需要在路由节点判断 Agent 的 State(字典)到底走到了哪一步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from typing import Any
from typing_extensions import TypedDict, TypeIs

class ErrorState(TypedDict):
error_code: int
message: str

class SuccessState(TypedDict):
result: str


def is_error_state(state: Any) -> TypeIs[ErrorState]:
return isinstance(state, dict) and "error_code" in state

def handle_graph_state(state: Any):
if is_error_state(state):

print(f"Agent 发生崩溃: {state['error_code']}")
return


4. 最终总结

当你拿到一个像盲盒一样的 Any 或者 dict 数据,且需要将其作为某种泛型或字典类型来使用时:

  1. 绝对不要用 cast(),那是在掩耳盗铃,出了 Bug 极难排查。
  2. 写一个校验函数,用 isinstance 和字典键检查把它的老底查清楚。
  3. 把这个函数的返回值标为 TypeIs[你要的类型]

这样,你既拥有了坚如磐石的运行时安全,又让 IDE 的静态检查发挥到了极致!