โพรโทคอล __enter__ และ __exit__
สร้างตัวจัดการบริบทด้วยโพรโทคอล dunder
โพรโทคอล __enter__ และ __exit__ เป็นบทเรียน Python Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Python Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน
โพรโทคอลตัวจัดการบริบท
อ็อบเจ็กต์ใดก็ตามที่กำหนด __enter__ และ __exit__ จะเป็นตัวจัดการบริบทและสามารถใช้ร่วมกับ with ได้
class Managed:
def __enter__(self):
print("entering")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("exiting")
return False
with Managed() as m:
print("inside")ค่าที่ส่งคืนโดย __enter__
__enter__ จะถูกเรียกเมื่อเริ่มต้นบล็อก with ค่าที่ส่งคืนจะถูกผูกกับตัวแปรหลัง as
class Resource:
def __enter__(self):
self.value = 42
return self # bound to 'r'
def __exit__(self, *args):
self.value = None
return False
with Resource() as r:
print(r.value) # 42อาร์กิวเมนต์ของ __exit__
__exit__(exc_type, exc_val, exc_tb) จะได้รับข้อมูลข้อยกเว้นหากเกิดข้อผิดพลาด หากไม่มีข้อยกเว้น ทั้งสามค่าจะเป็น None
class Safe:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is ValueError:
print(f"Suppressed ValueError: {exc_val}")
return True # suppress the exception
return False # re-raise anything else
with Safe():
raise ValueError("oops") # suppressedการระงับข้อยกเว้น
คืนค่า True จาก __exit__ เพื่อระงับข้อยกเว้น คืนค่า False หรือไม่คืนค่าใด ๆ เพื่อให้ข้อยกเว้นถูกส่งต่อ
class Ignore:
def __enter__(self): return self
def __exit__(self, *args): return True # swallow all exceptions
with Ignore():
1 / 0
print("continues here")ตัวอย่างการเชื่อมต่อฐานข้อมูล
กรณีใช้งานแบบคลาสสิกคือ ขอการเชื่อมต่อเมื่อเข้าสู่บริบท จากนั้น commit หรือ rollback และปิดการเชื่อมต่อเมื่อออกจากบริบท
class DBConn:
def __enter__(self):
self.conn = connect_db()
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
self.conn.rollback()
else:
self.conn.commit()
self.conn.close()
return Falseตัวจัดการบริบท Timer
วัดเวลาที่ผ่านไปโดยบันทึกเวลาเริ่มต้นใน __enter__ และคำนวณส่วนต่างใน __exit__
import time
class Timer:
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, *args):
self.elapsed = time.perf_counter() - self.start
print(f"Elapsed: {self.elapsed:.3f}s")
return False
with Timer():
sum(range(1_000_000))การซ้อนตัวจัดการบริบท
สามารถรวมตัวจัดการบริบทหลายตัวไว้ในบรรทัด with เดียวได้
with open("in.txt") as src, open("out.txt", "w") as dst:
dst.write(src.read())ตัวจัดการที่ใช้ซ้ำได้กับตัวจัดการที่ใช้ครั้งเดียว
ตัวจัดการบริบทที่ __enter__ จัดสรรทรัพยากรใหม่ทุกครั้งจะสามารถใช้ซ้ำได้ ส่วนตัวจัดการที่ใช้สถานะภายในจนหมด เช่น ล็อกที่ถือได้เพียงครั้งเดียว อาจไม่สามารถใช้ซ้ำได้
class Reusable:
def __enter__(self):
return []
def __exit__(self, *a):
return False
for _ in range(3):
with Reusable() as lst:
lst.append(1)
print(lst) # [1] each time__aenter__ และ __aexit__ (แบบอะซิงก์)
สำหรับตัวจัดการบริบทแบบอะซิงก์ ให้กำหนดคอรูทีน __aenter__ และ __aexit__ และใช้ async with
class AsyncDB:
async def __aenter__(self):
self.conn = await connect()
return self.conn
async def __aexit__(self, *args):
await self.conn.close()
# async with AsyncDB() as conn:
# ...การครอบอ็อบเจ็กต์ไฟล์
อ็อบเจ็กต์ไฟล์ของ Python มีการใช้งานโพรโทคอลตัวจัดการบริบทอยู่แล้ว จึงไม่ควรเรียก f.close() ด้วยตนเอง
with open("data.txt", "r") as f:
data = f.read()
# file is closed here automatically
print(f.closed) # Trueการใช้งาน Lock
ล็อกของเธรดเป็นตัวจัดการบริบท: __enter__ จะยึดล็อก และ __exit__ จะปล่อยล็อก
import threading
lock = threading.Lock()
def update_shared():
with lock:
# critical section
passตรวจสอบอย่างรวดเร็ว
ควรส่งคืนค่าใดจาก __exit__ เพื่อระงับข้อยกเว้น
สรุป
นำ __enter__ และ __exit__ มาใช้เพื่อสร้างตัวจัดการบริบท ส่งคืนทรัพยากรจาก __enter__ และจัดการการทำความสะอาดรวมถึงการระงับข้อยกเว้นใน __exit__
คำถามที่พบบ่อย
บทเรียน “โพรโทคอล __enter__ และ __exit__” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “โพรโทคอล __enter__ และ __exit__” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Python Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “โพรโทคอล __enter__ และ __exit__”
สร้างตัวจัดการบริบทด้วยโพรโทคอล dunder คุณปฏิบัติ Python Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Python Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Python Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “โพรโทคอล __enter__ และ __exit__” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Python Academy นี้ได้ไหม
ได้ บทเรียน Python Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เจาะลึกคำสั่ง with
- โพรโทคอล __enter__ และ __exit__
- contextlib: @contextmanager
- รูปแบบการใช้ตัวจัดการบริบทในทางปฏิบัติ