yarl.url 实例不可修改,因其设计为不可变对象,所有修改操作均返回新实例;此举保障线程安全与缓存友好,避免重复解析和同步开销。

为什么 yarl.URL 实例不能修改
因为设计上就是不可变对象——和 str、tuple 一样,所有修改操作(比如加路径、换参数)都返回新实例,原对象不变。这不是 bug,是刻意为之。
这么做的核心原因是线程安全和缓存友好:URL 解析开销不小,不可变性让 yarl 可以安全地缓存解析结果(比如 .host、.path),避免重复计算;也省去深拷贝或加锁的麻烦。
- 常见错误现象:
url.path = "/new"会直接报AttributeError: can't set attribute - 正确做法:用
.with_path()、.with_query()、.join()等方法生成新 URL - 别试图绕过:
object.__setattr__(url, "_path", ...)不仅破坏内部状态,还可能让缓存失效、引发后续ValueError
yarl.URL 和 urllib.parse.urlparse 的行为差异
两者根本不是一类东西:urllib.parse.urlparse 返回的是普通 ParseResult 元组,可读不可写;而 yarl.URL 是专为构建/组合 URL 设计的类,提供链式、语义化的方法,但代价是必须接受不可变性。
- 使用场景:拼接 API 地址时,
yarl更直观——base_url / "v1" / "users" % {"id": 123}比手动urljoin+urlencode少出错 - 参数差异:
yarl.URL("https://a.com").with_query({"k": "v"})会自动编码值,urllib.parse.urlencode默认不处理空格等字符,需额外传safe="" - 性能影响:首次构建
yarl.URL略慢(要解析并缓存),但后续取.host、.query_string是 O(1);urllib.parse每次访问属性都要重新解析
哪些操作会意外创建新对象
容易误以为“在改原对象”的地方,其实都在返回新实例——稍不注意就会丢掉结果。
易汛企业网站系统.Net出色的五大特性:灵活、易用、安全、稳定、可扩展性在业界备受瞩目。系统基于微软力荐 .Net 2.0 部署环境,其公认的高效、稳定、安全的特性将为您的网站注入一颗健壮的核心“CPU”!得力于微软不断完善、开发的 .NET 平台的新优势、高性能,为您网站的发展奠定了前沿尖端的技术基础。无论您的网站是刚刚建立,还是已经成长为信息门户,易汛企
立即学习“Python免费学习笔记(深入)”;
-
url / "api"→ 新 URL,原url不变 -
url.with_scheme("https")→ 新 URL,即使 scheme 没变 -
url % {"q": "py"}(即with_query)→ 新 URL,且会覆盖全部 query - 连
str(url)都触发一次完整序列化,不是廉价操作,高频日志里要注意
不可变性带来的真实麻烦点
最常卡住人的不是“不能改”,而是“忘了接返回值”或者“误判了缓存边界”。比如:
- 循环中反复
url = url.with_query(...)看似合理,但如果url初始是None或字符串,会直接崩在AttributeError - 用
is比较两个逻辑相等的 URL(如URL("a") / "b" is URL("a/b"))一定为False,得用== - 调试时打印
id(url)会发现每次操作后 ID 都不同,这是正常现象,不是内存泄漏
真正难处理的是嵌套构建逻辑——比如从配置拼 base URL,再根据条件加 path 和 query,中间任何一步漏了赋值,后面就全错。这时候不如拆成明确变量,别贪链式调用。









