Nếu bạn vẫn nối đường dẫn bằng os.path.join và kiểm tra file bằng os.path.exists, hãy thử pathlib.Path. Nó biến đường dẫn thành một đối tượng có sẵn phương thức đọc, ghi, tạo thư mục và duyệt file, nên code ngắn hơn, đọc xuôi hơn và ít lỗi sai dấu phân cách giữa Windows với Linux. Bài này áp dụng khi bạn viết script xử lý file, tool nội bộ hoặc bất kỳ đoạn code Python nào phải chạm tới hệ thống file.
Vấn đề
Với os.path, đường dẫn chỉ là chuỗi. Bạn phải nhớ đúng thứ tự đối số của join, tự nối dấu phân cách, rồi gọi thêm hàm khác mỗi khi muốn kiểm tra tồn tại, lấy tên file hay tạo thư mục. Code vì thế dài và rời rạc: một thao tác đơn giản như “tìm mọi file .txt trong cây thư mục rồi ghi kết quả ra một file mới” cũng cần kết hợp nhiều hàm, và chỉ cần quên một dấu / là đường dẫn đã sai.
import osroot = os.path.join("du-an", "data", "raw")files = [f for f in os.listdir(root) if f.endswith(".txt")]out = os.path.join("du-an", "ket-qua.txt")with open(out, "w", encoding="utf-8") as fh: fh.write("\n".join(files))
Giải pháp
pathlib.Path gói đường dẫn thành đối tượng. Toán tử / nối đường dẫn một cách trực quan, còn các phương thức như exists(), mkdir(), glob() hay read_text() nằm ngay trên chính đối tượng đó. Cùng một đoạn code chạy được cả trên Windows lẫn Linux vì Path tự xử lý dấu phân cách.
from pathlib import Pathroot = Path("du-an") / "data" / "raw"files = sorted(p.name for p in root.glob("*.txt"))out = Path("du-an") / "ket-qua.txt"out.write_text("\n".join(files), encoding="utf-8")print(out.exists(), out.suffix, out.parent.name)
Ngoài ví dụ trên, vài phương thức hay dùng nhất là mkdir(parents=True, exist_ok=True) để tạo cả cây thư mục, rglob("*.csv") để duyệt đệ quy, with_suffix(".json") để đổi đuôi file, relative_to() để lấy đường dẫn tương đối và resolve() để có đường dẫn tuyệt đối đã chuẩn hóa. Khi một hàm cũ bắt buộc nhận chuỗi, chỉ cần str(path) là xong — không cần viết lại toàn bộ code.
Áp dụng vào dự án của bạn
Đừng đổi một lúc cả codebase. Hãy bắt đầu từ những script mới hoặc đoạn code đang gây khó đọc nhất: chỗ nối đường dẫn, duyệt thư mục hay ghi file tạm. Thay từng chỗ bằng Path, chạy lại test hoặc chạy tay một lần để chắc chắn kết quả không đổi, rồi mới lan dần sang các module khác. Với các dự án đã có sẵn hàm nhận đường dẫn dạng chuỗi, bạn vẫn có thể truyền Path vào rồi chuyển đổi ở biên bằng str() khi cần, nên việc chuyển đổi gần như không có rủi ro.
Bài viết liên quan
- Python: viết class chứa dữ liệu gọn hơn 70% bằng @dataclass trong 5 phút
- Python: tăng tốc hàm tính toán lặp lại bằng @lru_cache và @cache trong 5 phút
- Python: gọi nhiều API song song bằng asyncio.gather và Semaphore trong 10 phút
Câu hỏi thường gặp
pathlib có thay thế hoàn toàn os.path không?
Gần như được, nhưng không bắt buộc. pathlib xử lý tốt hầu hết thao tác đường dẫn, còn một số hàm hệ thống cũ như os.listdir hay os.environ vẫn giữ nguyên vai trò của chúng. Bạn nên dùng Path cho đường dẫn và giữ os cho những việc còn lại.
Dùng Path có làm code chậm hơn không?
Không đáng kể với script thông thường. Path chỉ là một lớp bọc quanh chuỗi đường dẫn, chi phí tạo đối tượng rất nhỏ so với thời gian đọc, ghi hay duyệt file thật. Chỉ khi bạn tạo hàng triệu đối tượng Path trong vòng lặp cực nóng mới cần đo lại bằng timeit.
Làm sao để lấy lại chuỗi đường dẫn từ Path?
Dùng str(path) khi hàm nhận vào yêu cầu chuỗi, hoặc path.as_posix() khi bạn cần chắc chắn dấu phân cách là /, ví dụ lúc ghi đường dẫn vào file cấu hình hay log dùng chung giữa các hệ điều hành.
Nên dùng Path hay os.path trong dự án cũ?
Dùng Path cho code mới và những đoạn đang sửa. Với code cũ đang chạy ổn, không cần đổi hàng loạt — chỉ chuyển đổi khi bạn chạm vào đoạn đó vì một lý do khác, để tránh tạo ra thay đổi không cần thiết.
💬 Bạn đã thử cách này trong dự án của mình chưa? Nếu gặp lỗi hoặc có cách làm gọn hơn, để lại bình luận bên dưới — mình đọc hết và sẽ bổ sung những ý hay vào bài.
Nguồn tham khảo
- Tài liệu chính thức Python, module pathlib: https://docs.python.org/3/library/pathlib.html
