os.path.join과 문자열 자르기로 경로를 다루다가 pathlib으로 정리
문제 발생
파일 경로를 다루는 코드가 문자열 조작으로 가득했습니다. 확장자를 바꾸는 부분은 특히 취약했습니다.
import os
path = os.path.join(base, "reports", name + ".csv")
stem = os.path.splitext(os.path.basename(path))[0]
out = os.path.join(os.path.dirname(path), stem + ".json")
os.makedirs(os.path.dirname(out), exist_ok=True)
with open(path) as f:
content = f.read()name에 점이 들어 있으면 splitext의 결과가 달라졌고, 윈도우에서 구분자가 섞이는 문제도 있었습니다.
원인 분석
os.path는 경로를 문자열로 다룹니다. 그래서 결합, 분해, 확장자 교체가 전부 문자열 연산이고, 그 연산 각각이 실수할 자리입니다. 구분자도 직접 신경 써야 합니다.
pathlib은 경로를 객체로 다룹니다. 결합에는 / 연산자를 쓰고, 구성 요소는 속성으로 읽으며, 파일 읽기·쓰기와 디렉터리 생성 메서드를 경로 객체 자신이 갖고 있습니다.
해결 방안
- 결합은
/연산자로 합니다.
from pathlib import Path
path = Path(base) / "reports" / f"{name}.csv"- 구성 요소는 속성으로 읽습니다. 문자열을 자르지 않습니다.
p = Path("my/library.tar.gz")
p.name # 'library.tar.gz'
p.stem # 'library.tar'
p.suffix # '.gz'
p.suffixes # ['.tar', '.gz']
p.parent # Path('my')- 확장자 교체는
with_suffix입니다. 마지막 확장자만 바꾸므로 이름에 점이 있어도 안전합니다.
out = path.with_suffix(".json")
Path("README").with_suffix(".txt") # README.txt (없으면 붙인다)
Path("README.txt").with_suffix("") # README (빈 문자열이면 제거)- 디렉터리 생성과 파일 입출력을 경로에서 바로 합니다.
out.parent.mkdir(parents=True, exist_ok=True)
content = path.read_text(encoding="utf-8")
out.write_text(json.dumps(data), encoding="utf-8")- 탐색은
glob/rglob을 씁니다.rglob은 재귀 탐색입니다.
for csv in Path("data").rglob("*.csv"):
...- 존재 확인과 정규화도 메서드입니다.
exists(),is_file(),is_dir()은 예외 없이 불린을 돌려주고,resolve()는 심볼릭 링크와..을 정리한 절대 경로를 만듭니다. 사용자 입력으로 만든 경로를 다룰 때는resolve()후 기준 디렉터리 안에 있는지 확인하는 것이 경로 탈출을 막는 기본 검사입니다. - 문자열이 필요한 곳에는
str(path)를 씁니다. 대부분의 표준 라이브러리는Path를 그대로 받지만, 오래된 서드파티 함수는 문자열을 요구하기도 합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.