Context Manager (with statement)
Файл нээх, өгөгдлийн сантай холбогдох, сүлжээ ашиглах үед нөөцийг зөв хаах маш чухал. Хэрэв алдаа гарч нөөц хаагдаагүй бол санах ой дуусах, файл гэмтэх зэрэг асуудал үүснэ. with statement нь үүнийг автоматаар зохицуулдаг.
Яагаад with ашиглах вэ?
Файлтай ажиллах хоёр аргыг харьцуулъя:
# Муу арга — алдаа гарвал файл хаагдахгүй
файл = open("өгөгдөл.txt", "r")
агуулга = файл.read()
файл.close() # алдаа гарвал энэ мөр ажиллахгүй!
# Сайн арга — with автоматаар хаана
with open("өгөгдөл.txt", "r") as файл:
агуулга = файл.read()
# блок дууссаны дараа файл автоматаар хаагдана
# алдаа гарсан ч гэсэн!
with блок дуусахад — амжилттай ч, алдаатай ч — Python файл.close() дуудахаа баталгааждаг.
Context Manager хэрхэн ажилладаг
with ашиглах объект нь __enter__ ба __exit__ методтой байх ёстой. Эдгээр нь dunder методууд — өмнөх хичээлд үзсэн ойлголт.
class МэдрэгчНөөц:
def __enter__(self):
print("Нөөц нээгдлаа")
return self # "as" хувьсагчид хариуцагдана
def __exit__(self, exc_type, exc_val, exc_tb):
print("Нөөц хаагдлаа")
return False # алдааг дамжуулна
def унших(self):
return "өгөгдөл"
with МэдрэгчНөөц() as нөөц:
print(нөөц.унших())
# Нөөц нээгдлаа
# өгөгдөл
# Нөөц хаагдлаа
__exit__ нь алдаа гарсан ч дуудагдана. return True буцаавал алдааг залгиж дарна, return False буцаавал алдааг дамжуулна.
contextlib.contextmanager — generator аргаар
contextlib модуль ашиглан decorator + generator хослолоор context manager бичих илүү хялбар арга байдаг:
from contextlib import contextmanager
@contextmanager
def хугацаа_хэмжих(нэр):
import time
эхлэл = time.time()
print(f"'{нэр}' эхэллаа...")
yield # with блок энд ажиллана
өнгөрсөн = time.time() - эхлэл
print(f"'{нэр}' дууслаа: {өнгөрсөн:.3f}с")
with хугацаа_хэмжих("өгөгдөл боловсруулалт"):
sum(range(5_000_000))
# 'өгөгдөл боловсруулалт' эхэллаа...
# 'өгөгдөл боловсруулалт' дууслаа: 0.182с
yield-ийн өмнөх код нь __enter__, дараах код нь __exit__ үүрэг гүйцэтгэнэ.
Олон нөөц нэгэн зэрэг нээх
Python 3 дээр нэг with блокт хэд хэдэн нөөц нээж болно:
with open("оролт.txt", "r") as орох, open("гаралт.txt", "w") as гарах:
агуулга = орох.read()
гарах.write(агуулга.upper())
# хоёр файл хоёулаа автоматаар хаагдана
Бодит хэрэглээ
Context manager нь практикт маш өргөн хэрэглэгддэг:
| Хэрэглээ | Жишээ |
| --- | --- |
| Файл | open() |
| Өгөгдлийн сан | sqlite3.connect() |
| Сүлжээ | socket.socket() |
| Түгжээ (thread) | threading.Lock() |
| Тест тусгаарлалт | unittest.mock.patch() |
Эдгээр бүгд with ашиглан нөөцийг аюулгүй зохицуулдаг — try/finally гар аргаар бичихгүйгээр.
Дараагийн хичээлд:
Тогтмол илэрхийлэл (RegExp) — мөрөөс хэв загвар хайх, задлах, орлуулах re модулийг сурна.