Path objects make file code shorter, more readable and portable compared with string juggling.
from pathlib import Path gives you the class you'll use almost all the time. Path("data/input.csv") creates a path object; on Windows it becomes a WindowsPath, elsewhere a PosixPath, but you rarely need to care.
Join paths with the / operator:
base = Path("data")
report = base / "2024" / "report.csv"Strings can appear on either side ("logs" / Path("x") works too), and the right separator is used for the platform. As with os.path.join, joining an absolute path discards what came before: Path("data") / "/etc" is /etc.
Useful starting points:
Path.cwd()the current working directoryPath.home()the user's home directoryPath(__file__).parentthe folder containing the current module, the reliable base for files shipped with your code
str(p) converts back to a string when an API really needs one, but nearly all of the standard library (open, os, shutil, subprocess, json...) accepts Path objects directly, because Path implements the os.PathLike protocol.
Paths are immutable and hashable: methods return new paths, and you can use them as dict keys or in sets. Comparing paths compares their parts, case-insensitively on Windows.
Example
from pathlib import Path
base = Path("data")
report = base / "2024" / "report.csv"
print(report) # data/2024/report.csv
print(type(report).__name__) # PosixPath
print(Path("data") / "/etc") # /etc
print(Path.home().is_absolute()) # True
print(Path.cwd() == Path(".").resolve()) # True
seen = {Path("a/b"), Path("a") / "b"}
print(len(seen)) # 1
here = Path(__file__).parent if "__file__" in globals() else Path.cwd()
print(here.is_dir()) # TrueRemember
Path(...) / 'name'joins paths portablyPath.cwd(),Path.home()andPath(__file__).parentare common bases- Paths are immutable, hashable and accepted by open, os and shutil
Watch out for
- Concatenating strings with '/' and passing them around instead of keeping Path objects.