
contextlib.chdir: เปลี่ยนโฟลเดอร์ชั่วคราวแบบปลอดภัยใน with
เคยเขียนสคริปต์ที่ os.chdir เข้าไปทำงานในโฟลเดอร์ชั่วคราว แล้วลืมเปลี่ยนกลับไหม ผมเคยจนพาเทสต์อื่นพังตาม
ตั้งแต่ Python 3.11 มี contextlib.chdir เป็น context manager ที่เปลี่ยน working directory ตอนเข้า with แล้วคืนค่าเดิมตอนออก แม้มี exception
ทำไมไม่ใช้ os.chdir อย่างเดียว
os.chdir เปลี่ยนสถานะโปรเซสทั้งก้อน ถ้าลืมคืนค่า หรือมีหลายเธรดแย่งกัน งานอื่นที่พึ่ง path สัมพัทธ์จะเพี้ยน chdir ใน contextlib อย่างน้อยช่วยให้ขอบเขตชัดในโค้ดแบบซิงเกิลเธรด
เอกสารเตือนว่าการเปลี่ยน cwd ทั้งโปรเซสยังไม่เหมาะกับ multithreaded อยู่ดี — ถ้าทำขนานจริง ควรส่ง path สัมบูรณ์เข้าฟังก์ชันแทน
from __future__ import annotations
import os
import tempfile
import unittest
from contextlib import chdir
from pathlib import Path
class ChdirTests(unittest.TestCase):
def test_restores_cwd(self):
original = Path.cwd()
with tempfile.TemporaryDirectory() as tmp:
target = Path(tmp).resolve()
with chdir(target):
self.assertEqual(Path.cwd(), target)
self.assertEqual(Path.cwd(), original)
def test_restores_after_error(self):
original = Path.cwd()
with tempfile.TemporaryDirectory() as tmp:
target = Path(tmp).resolve()
with self.assertRaises(RuntimeError):
with chdir(target):
self.assertEqual(Path.cwd(), target)
raise RuntimeError("boom")
self.assertEqual(Path.cwd(), original)
if __name__ == "__main__":
unittest.main()
Recap
- ใช้
with chdir(path):เมื่อต้องรันเครื่องมือที่อ่าน cwd - อย่าพึ่ง chdir ในโค้ด multithreaded — ส่ง absolute path แทน
- ทดสอบว่าออกจาก
withแล้ว cwd กลับจริง รวมกรณีมี exception