应使用 os.path.samefile() 判断两路径是否指向同一文件,因其通过比对 inode 和设备号实现,能正确处理软链接、挂载点等场景;字符串比较或 os.path.abspath() 不可靠,且必须捕获 OSError 异常。

直接用 os.path.samefile(),别用字符串比较或 ==。 路径字符串相同不代表是同一个文件(比如软链接、挂载点、大小写敏感系统),字符串不同也不代表不是同一个文件(比如 ./file 和 /home/user/file)。关键在 inode + 设备号,os.path.samefile() 就是干这个的。
为什么不能用字符串相等或 os.path.abspath() 比较?
路径字符串相等只是表象。Linux/macOS 下软链接、bind mount、case-insensitive APFS 卷都可能让两个不同字符串指向同一 inode;Windows 下还有重解析点、卷挂载、UNC 路径映射等问题。os.path.abspath() 只做路径规范化,不查文件系统元数据,对符号链接默认不解析(除非加 realpath=True),依然不可靠。
常见错误现象:
- 两个路径一模一样但
os.path.samefile()报OSError: [Errno 2] No such file or directory—— 至少一个路径不存在或没权限读取 stat - 在 Docker 容器里判断宿主机挂载的文件总失败 —— 容器内外设备号可能不同(如 overlayfs),此时需配合
os.stat().st_dev和st_ino手动比对,但要小心跨文件系统场景
os.path.samefile() 的正确用法和边界条件
它内部调用 os.stat() 并比对 st_dev 和 st_ino。必须确保两个路径都可访问且有权限获取 stat 信息。
立即学习“Python免费学习笔记(深入)”;
- 参数是两个字符串路径,支持相对路径、绝对路径、含
~的路径(但不会自动展开,得先用os.path.expanduser()) - 如果任一路径不存在、无权限、是断开的软链接,会抛
OSError,必须捕获处理 - 在 Windows 上也能用,底层比对的是对象 ID 或 volume serial + file index,行为一致
- 不自动解析符号链接 —— 这是优点:你想知道“这两个路径是否指向磁盘上同一份数据”,而不是“它们展开后是不是同一个路径”
示例:
import os
try:
if os.path.samefile("/tmp/foo", "./tmp/foo"):
print("same file")
except OSError as e:
print(f"can't compare: {e}")
需要解析符号链接时怎么办?
如果你关心的是“最终指向的是否为同一目标”,而不是“当前路径句柄是否指向同一 inode”,那就该用 os.path.realpath() 先归一化,再用 == 比较字符串 —— 但仅限于你确定所有路径都存在、且不需要跨设备/挂载点判断的简单场景。
-
os.path.realpath()会递归解析所有符号链接,返回绝对路径 - 结果路径字符串相等,基本可认为是同一目标(仍要注意 Windows 驱动器大小写、网络路径映射等例外)
- 如果其中一个路径根本不存在,
realpath()会静默忽略不存在的部分,导致错误结果 —— 比如realpath("nonexistent/file")返回"nonexistent/file",和真实存在的路径比较就误判 - 性能略低:每次都要遍历路径组件、读取目录项、解析链接
所以,除非明确业务逻辑要求“跟随链接”,否则优先用 samefile()。
真正容易被忽略的是错误处理 —— 很多人只写 samefile(a, b),却没包 try/except,一旦遇到权限不足或路径不存在,程序就崩了。inode 和设备号比对本身很快,但前提是你得先能拿到它们。


















