2.24. Context managers¶
คำสั่ง with รันโค้ดการตั้งค่า จากนั้นเนื้อหา แล้วโค้ดการล้างข้อมูล -- พร้อมรับประกันว่าการล้างข้อมูลจะทำงานแม้เนื้อหาล้มเหลวระหว่างทาง คู่ของเมธอดที่ให้การตั้งค่าและการล้างข้อมูลเรียกว่า context manager
รูปแบบคือ:
with <expression> as <name>:
<body>
นิพจน์จะคืนค่า context manager Python เรียกเมธอด __enter__ ของมัน โดยอาจผูกผลลัพธ์กับ <name> รันเนื้อหา แล้วจึงเรียก __exit__ ไม่ว่าเนื้อหาจะทำงานสำเร็จหรือเกิดข้อยกเว้น
__exit__ ทำงานเมื่อสิ้นสุดบล็อกไม่ว่าจะเกิดอะไรขึ้นภายใน¶
2.24.1. การใช้งาน context manager¶
ตัวอย่างทั่วไปคือการเปิดไฟล์:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() คืนค่าออบเจ็กต์ไฟล์ที่ตัวมันเองเป็น context manager __enter__ คืนค่าไฟล์ และ __exit__ ปิดมัน บล็อก with ทำให้ "ปิดไฟล์เสมอเมื่อเสร็จสิ้น" เป็นค่าเริ่มต้นแทนที่จะเป็นสิ่งที่ผู้เรียกต้องจำเอง
2.24.1.1. Context manager หลายตัว¶
คำสั่ง with เดียวสามารถเข้า context manager หลายตัวพร้อมกันได้โดยใช้เครื่องหมายจุลภาคคั่น:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
เทียบเท่ากับบล็อก with ซ้อนกันสองชั้น แต่แบนกว่า Manager จะถูกเข้าจากซ้ายไปขวาและออกในลำดับย้อนกลับ ถ้า __enter__ ของ manager ฝั่งขวาเกิดข้อยกเว้น __exit__ ของ manager ฝั่งซ้ายก็ยังทำงาน
2.24.2. การเขียน context manager¶
คลาสใดก็ตามที่มีเมธอด __enter__ และ __exit__ สามารถใช้งานเป็น context manager ได้:
class Section:
def __init__(self, label):
self.label = label
def __enter__(self):
print("---", self.label, "---")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("--- end", self.label, "---")
return False
with Section("setup"):
print("doing the work")
ผลลัพธ์:
--- setup ---
doing the work
--- end setup ---
__exit__ รับอาร์กิวเมนต์สามตัวที่อธิบายข้อยกเว้นที่ทำให้บล็อกสิ้นสุด หรือค่า None สามค่าถ้าบล็อกทำงานสำเร็จ การคืนค่า False (หรือ None) จะปล่อยให้ข้อยกเว้นใดๆ แพร่กระจายหลังการล้างข้อมูล การคืนค่า True จะระงับข้อยกเว้นนั้น
ใช้ context manager สำหรับทรัพยากรใดก็ตามที่มีวงจรชีวิต "เปิด / ปิด" หรือ "ได้รับ / ปล่อย" -- ไม่ใช่แค่ไฟล์ รูปแบบนี้ทำให้การล้างข้อมูลอยู่คู่กับการตั้งค่า ณ จุดที่ทั้งคู่ถูกแนะนำ ดังนั้นการลืมปิดในกลางฟังก์ชันยาวๆ จึงไม่ทำให้ทรัพยากรรั่วไหล