管用,但仅当路径已存在且为目录时静默跳过;若路径是文件或父级为文件,仍抛FileExistsError或OSError。
os.makedirs 的 exist_ok 参数到底管不管用?管用,但只在「目标路径是目录且已存在」时生效;如果路径已存在且是文件,os.makedirs 仍会抛 FileExistsError。这是最常被误解的一点——很多人以为设了 exist_ok=True 就能“完全静默”,结果在部署脚本里突然崩了。
常见错误现象:FileExistsError: [Errno 17] File exists: '/path/to/log',而 /path/to/log 实际上是个普通文件(比如日志文件被提前 touch 出来了),不是目录。
exist_ok=True 不会覆盖、不尝试删除、不重命名,它只跳过「创建目录」动作本身/tmp 被误写成文件),也会立即报错,不会走到最后一级try/except
安全做法是:先用 os.path.exists 检查,再用 os.path.isdir 确认是不是目录,最后决定是否调用 os.makedirs。绕过 exist_ok 的语义盲区。
示例逻辑:
import osdef safe_makedirs(path): if os.path.exists(path): if not os.path.isdir(path): raise NotADirectoryError(f"Cannot create directory: {path} exists and is not a directory")
已是目录,无需操作
return os.makedirs(path, exist_ok=True)
os.path.isdir(path) 判断——路径不存在时它也返回 False,容易误删或跳过NotADirectoryError 更准确,比泛用 Exception 更利于下游捕获处理os.unlink(path) + os.makedirs,但务必加注释说明风险
pathlib.Path.mkdir 的 exist_ok 行为一致吗?
行为完全一致:Python 3.4+ 的 pathlib.Path.mkdir(parents=True, exist_ok=True) 同样只对「已存在且为目录」静默,遇到同名文件照样抛 FileExistsError。
所以换写法不解决问题,只是语法糖。但 pathlib 在组合路径时更健壮(自动处理斜杠、跨平台),推荐用于新项目:
from pathlib import Pathp = Path("/var/log/myapp") p.mkdir(parents=True, exist_ok=True) # 同样不解决“路径是文件”的情况
parents=True 是必须的,否则父目录不存在时直接失败(os.makedirs 默认就是递归)p.mkdir(exist_ok=True) 代替 p.parent.mkdir(...) 来建父目录——它只作用于 p 自身os.makedirs 一样,不处理权限(mode 参数受 umask 影响),生产环境建议显式设 mode=0o755
mkdir -p 报错?Linux/macOS 的 mkdir -p 本身就不抛错——它遇到已存在目录直接忽略,遇到同名文件则报 mkdir: cannot create directory ‘xxx’: File exists,行为和 Python 完全对应。
所以 shell 脚本里也得防御性检查:
if [ -e "$DIR" ] && [ ! -d "$DIR" ]; then echo "Error: $DIR exists but is not a directory" >&2 exit 1 fi mkdir -p "$DIR"
[ -d "$DIR" ] || mkdir -p "$DIR" ——当 $DIR 不存在时,-d 返回 false,会执行 mkdir;但当它是文件时,-d 也返回 false,同样会执行 mkdir 并失败[ -e ] 和 [ -d ] 必须分开判断,顺序不能反(先 -e 再 -d)[[,坚持用 [ 更稳妥实际用的时候,最容易被忽略的是:你写的函数或脚本,可能跑在别人已经预置了同名文件的环境里。这时候 exist_ok=True 不是银弹,而是个温柔的陷阱。