大家好,我是 SiKi老师。资源清单里有的写成assets/icons/hero.png,有的直接贴了本机绝对路径,工具一跑就报找不到文件;或者把绝对路径再拼到项目根后面,路径变成“根目录 + 又一段绝对路径”的怪物串。先别改资源文件本身,我会先定一个项目根目录,再按“相对挂到根下、绝对原样解析”把入口统一。
本文在 Linux 上的 Python 3.12.15 中运行,另用 3.13.5 复跑同一脚本,下面引用的输出两边一致。演示只在临时目录里自拟project/assets/icons/hero.png,不读写真实游戏资源。官方在线文档页面标注的小版本是 3.12.16,与本机 3.12.15 差一个补丁号,正文以本机实测为准。
一 先固定项目根,再谈相对还是绝对
自拟一个小工程树,并准备两种清单写法:
frompathlibimportPathimporttempfilewithtempfile.TemporaryDirectory()astmp:root=Path(tmp)/"project"icon=root/"assets"/"icons"/"hero.png"icon.parent.mkdir(parents=True)icon.write_bytes(b"fake-png-bytes")rel="assets/icons/hero.png"abs_entry=str(icon.resolve())print(rel)print(abs_entry)相对路径离开“当前工作目录”或“约定的根”就没有意义;绝对路径看起来完整,但换机器、换盘符就会失效。工具协议里应写清:清单里的相对路径相对于哪个根。下面统一用root表示这个根。
二 不要用字符串把绝对路径再拼到根后面
常见翻车是把绝对路径当相对段做裸拼接:
bad=str(root)+"/"+abs_entryprint(bad)print(Path(bad).exists())本地会得到类似/tmp/.../project//tmp/.../project/assets/icons/hero.png,exists()为False。缺分隔符时更糟:str(root) + "assets/..."会变成.../projectassets/...,同样找不到。
os.path.join和Path的/运算在遇到绝对后段时,会丢掉前面的根(与官方对 join 行为的说明一致):
importosprint(os.path.join(str(root),abs_entry))print(root/abs_entry)在本机 Linux 上,这两行都会落回那条绝对路径本身,文件能找到,但这是“后段吞掉前段”,不是“挂到根下”。若你本意是强制所有资源都在根目录内,这种静默丢根反而会放过越界路径,需要另做is_relative_to校验。
三 用同一套规则解析相对和绝对
推荐入口函数:相对路径挂到根下再resolve;已经是绝对路径则直接resolve:
defresolve_under_root(project_root:Path,entry:str)->Path:p=Path(entry)ifp.is_absolute():returnp.resolve()return(project_root/p).resolve()got_rel=resolve_under_root(root,rel)got_abs=resolve_under_root(root,abs_entry)print(got_rel.exists(),got_abs.exists(),got_rel==got_abs)本地两者都存在且路径相等。展示给策划或写回清单时,可用relative_to收成相对形式:
print(got_rel.relative_to(root.resolve()).as_posix())# assets/icons/hero.png拼接相对段时,优先root / "assets" / "icons" / "hero.png",或os.path.join(str(root), "assets", "icons", "hero.png"),不要自己拼斜杠。
四 换了当前工作目录也不能靠“碰巧”
有的工具依赖“先 chdir 到工程再读相对路径”。更稳的是始终带着 root:
importos old=Path.cwd()try:os.chdir(tmp)# 故意离开工程目录again=resolve_under_root(root,rel)print(again.exists())finally:os.chdir(old)本地在 chdir 之后仍为True,因为解析没有依赖进程当前目录。清单生成、批处理、CI 换目录时,这一条能少掉一批“我本地好好的”问题。
本文只在临时目录自拟资源,不联网,不碰真实游戏资源树。Windows 盘符与大小写规则未在本轮实测,不能把 Linux 路径字符串直接当 Windows 结论。
五 用回归样例锁住路径边界
本次独立验证脚本覆盖:相对/绝对统一解析到同一文件、裸字符串把绝对路径拼到根下会失败、缺分隔符拼接失败、os.path.join/Path遇绝对后段丢前段、relative_to展示、以及 chdir 后仍可按根解析。建议工具回归至少包含:
- 清单两项(相对 + 绝对)解析后
samefile或路径相等。 - 禁止
root_str + "/" + abs_str这类裸拼接进入正式路径。 - 解析结果若要求必须在根内,再用
is_relative_to(root.resolve())卡住越界绝对路径。
你清单里是相对多、还是绝对多?可以贴一条自拟的相对项、一条绝对项和当前拼接写法,我们一起看该统一成哪种协议。
依据:Python 3.12 pathlib 模块(docs.python.org/3.12/library/pathlib.html)关于 Path 拼接、resolve、relative_to,以及与 os.path.join 对应关系的说明。示例和表达原创,不引用具体课程信息。