Ачааллж байна...
Өмнөх хичээлд бид дэлгүүрийн алдааны шатлал бүтээж, дуудагч тал аль түвшинд барихаа сонгох боломж олгосон. Тэр хичээлийн жишээнүүдэд алдаа ихэвчлэн шинээр төрж байсан: place_order нөөцийг шалгаад OutOfStockError шидсэн. Бодит програмд алдаа ихэвчлэн өөр алдааны үр дагавар болж төрдөг. Төлбөрийн функц банкны сервер рүү хүсэлт илгээдэг бөгөөд сүлжээ тасарвал Python-ий бэлэн TimeoutError эсвэл ConnectionError гарна. Дэлгүүрийн бусад код тэр доод түвшний алдааг мэдэх ёсгүй: тэдний хувьд энэ бол PaymentTimeoutError, Хичээл 11.1-ийн шатлалын гишүүн. Тэгэхээр төлбөрийн функц доод түвшний алдааг барьж, өөрийн алдаа болгон дээш дамжуулах ёстой.
Энд нэг асуудал гарна. Хэрэв бид энгийнээр шинэ алдаа шидвэл анхны алдаа юу байсан бэ, аль мөрөнд гарсан бэ гэсэн мэдээлэл яах вэ? Debug хийж буй хөгжүүлэгч "төлбөр хугацаа хэтэрлээ" гэсэн мессежийг хараад "яагаад?" гэж асууна. Хариулт нь анхны TimeoutError ба түүний traceback-д байгаа. Python энэ асуудлыг exception chaining буюу "алдааны гинж"-ээр шийддэг: шинэ алдаа анхны алдааг өөртөө "шалтгаан" болгон хадгалж, traceback хоёуланг нь харуулдаг. Үүнийг тодорхой хийх бичлэг бол raise from.
Энэ хичээлийн хамгийн чухал ур чадвар нь уншиж чадах. Хичээл 2.1-т бид generator дотор StopIteration шидэхэд хоёр exception-тэй хачин traceback гарч, дунд нь “The above exception was the direct cause of the following exception” гэсэн мөр байсныг харсан. Тэр үед бид түүнийг Бүлэг 11-д бүрэн уншина гэж амласан. Энэ хичээлд тэр амлалтыг биелүүлнэ. Мөн Python-ий өөр нэг гинжин мессеж болох “During handling of the above exception, another exception occurred”-ийг ялгаж сурна. Энэ хоёр мөрийн ялгаа "санаатай орчуулсан алдаа" ба "алдааг барих явцад гарсан шинэ алдаа" хоёрын ялгаа бөгөөд debug хийхэд шийдвэрлэх ач холбогдолтой.
Эмнэлгийн тусламжийн дуудлагын бүртгэлийг төсөөлөөд үзээрэй. Хөдөөний эмнэлэгт өвчтөн ирж, эмч "зүрхний хэм алдагдал" гэж оношлоод, түүнийг хотын төв эмнэлэг рүү шилжүүлнэ. Төв эмнэлгийн эмч өвчтөнийг хүлээн авахдаа хоёр зүйл хүлээн авна: өвчтөн өөрөө, мөн хөдөөний эмнэлгийн илгээх бичиг: тэнд юу ажиглагдсан, ямар шинжилгээ хийгдсэн, яагаад шилжүүлсэн. Төв эмнэлэг өөрийн оношийг тавина, гэхдээ илгээх бичиг хавсаргагдсан хэвээр. Хэрэв хожим асуудал гарвал эмч нар бүрэн түүхийг эхнээс нь уншиж чадна.
Одоо илгээх бичиггүй шилжүүлэгийг төсөөлөөд үзээрэй. Төв эмнэлэг өвчтөнийг хүлээн авсан ч яагаад ирсэн, өмнө юу болсныг мэдэхгүй. Шинжилгээг бүгдийг дахин хийх, эсвэл буруу таамаглал гаргах хэрэгтэй болно.
raise from бол илгээх бичиг. Төлбөрийн функц доод түвшний TimeoutError-ийг "оношилж", PaymentTimeoutError болгон дээш "шилжүүлнэ", гэхдээ анхны алдааг шалтгаан болгон хавсаргана. Зүйрлэлд гурав дахь тохиолдол ч бий: шилжүүлэх явцад түргэн тусламжийн машин осолд орсон. Энэ бол шинэ, төлөвлөгдөөгүй асуудал, анхны өвчинтэй холбоотой ч санаатай шилжүүлэг биш. Python энэ хоёр тохиолдлыг ялгаж, traceback-д өөр өөр мөрөөр бичдэг.
Банкны сервер рүү хүсэлт илгээдэг функцийг дуурайлгая. Бодит програмд энэ нь HTTP хүсэлт байх бөгөөд Бүлэг 15-д бид жинхэнэ сүлжээний хүсэлт илгээнэ. Одоохондоо функц ердөө TimeoutError шиднэ. TimeoutError бол Python-ий бэлэн exception, үйлдэл хугацаандаа дуусаагүй үед гардаг.
python
class ShopError(Exception):
"""Дэлгүүрийн бүх алдааны эх."""
class PaymentError(ShopError):
"""Төлбөрийн системтэй холбоотой алдаа."""
class PaymentTimeoutError(PaymentError):
"""Төлбөрийн систем хариу өгөөгүй."""
def send_request(amount):
raise TimeoutError("банкны сервер 5 секундэд хариу өгсөнгүй")
def charge(order_id, amount):
try:
return send_request(amount)
except TimeoutError as error:
raise PaymentTimeoutError(f"#{order_id}: төлбөр хугацаа хэтэрлээ") from error
charge(1001, 50800)Ажиллуулахад:
Traceback (most recent call last):
File "C:\python-gunzgii\payment.py", line 19, in charge
return send_request(amount)
File "C:\python-gunzgii\payment.py", line 14, in send_request
raise TimeoutError("банкны сервер 5 секундэд хариу өгсөнгүй")
TimeoutError: банкны сервер 5 секундэд хариу өгсөнгүй
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\python-gunzgii\payment.py", line 24, in <module>
charge(1001, 50800)
File "C:\python-gunzgii\payment.py", line 21, in charge
raise PaymentTimeoutError(f"#{order_id}: төлбөр хугацаа хэтэрлээ") from error
PaymentTimeoutError: #1001: төлбөр хугацаа хэтэрлээPython-ий хувилбараас хамааран зарим мөрийн доор ^ эсвэл ~ тэмдгүүд нэмэлтээр харагдаж болно. Бүтэц нь ижил.
charge доод түвшний алдааг except-ээр барьж, шинэ PaymentTimeoutError шидсэн. from error хэсэг бол гол: "энэ шинэ алдааны шалтгаан нь error" гэсэн утгатай. Python үүнийг шинэ алдааны __cause__ attribute-д хадгалдаг.
Trace: гинжин traceback-ийг унших
Course 4-өөс хойш бид traceback-ийг доороос дээш уншиж сурсан: хамгийн сүүлийн мөр алдааны нэр ба мессеж, дээрх мөрүүд түүнд хүргэсэн дуудлагууд. Гинжин traceback-д энэ дүрэм бага зэрэг өргөжнө. Traceback хоёр блоктой, тус бүр өөрийн “Traceback (most recent call last):” гарчигтай, дунд нь холбох мөр. Блок бүрийг дотроо доороос дээш уншина, харин блокуудын дараалал цаг хугацааны дагуу: эхний блок эхэлж болсон алдаа.
Блок 1 (анхны шалтгаан). Доороос: “TimeoutError: банкны сервер 5 секундэд хариу өгсөнгүй”. Дээш: энэ алдаа send_request-ийн 14-р мөрөнд гарсан, түүнийг charge-ийн 19-р мөр дуудсан. Энэ блок <module> мөргүй гэдгийг анзаараарай: тэр зөвхөн алдаа гарсан газраас түүнийг барьсан газар хүртэлх замыг харуулдаг, charge-ийн try блок хүртэл.
Холбох мөр. “The above exception was the direct cause of the following exception”: "дээрх exception нь доорх exception-ий шууд шалтгаан болсон". “Direct cause” гэсэн үг нь raise from-ийн гарын үсэг: хөгжүүлэгч энэ холбоог санаатайгаар тогтоосон. Зүйрлэлийн илгээх бичиг.
Блок 2 (эцсийн алдаа). Доороос: “PaymentTimeoutError: #1001: төлбөр хугацаа хэтэрлээ”. Дээш: энэ алдаа charge-ийн 21-р мөрөнд, from-тэй raise дээр шидэгдсэн, charge-ийг модулийн 24-р мөр дуудсан.
Тэгэхээр бүрэн түүх: “24-р мөр charge-ийг дуудсан, charge send_request-ийг дуудсан, банкны сервер хариу өгөөгүй тул TimeoutError гарсан, charge түүнийг барьж PaymentTimeoutError болгон орчуулсан, тэр нь програмыг зогсоосон”. Хоёр блокийг нийлүүлэхэд хэн ч бүрэн замыг харж чадна. Debug хийх хөгжүүлэгч эцсийн алдаанаас эхэлж, "яагаад" гэдгийг мэдэхийн тулд дээд блок руу авирна: жинхэнэ шалтгаан ихэвчлэн гинжийн хамгийн эхэнд байдаг.
Шалтгааныг кодоос ч уншиж болно:
python
try:
charge(1001, 50800)
except PaymentError as error:
print("Алдаа:", error)
print("Шалтгаан:", repr(error.__cause__))Алдаа: #1001: төлбөр хугацаа хэтэрлээ
Шалтгаан: TimeoutError('банкны сервер 5 секундэд хариу өгсөнгүй')__cause__ нь raise from-оор хавсаргасан анхны алдааны объект. Дэлгүүрийн код PaymentError-ийг барьж, хэрэглэгчид ойлгомжтой мессеж харуулж, харин бүртгэлд шалтгааныг ч бичиж болно.
Хичээл 2.1-ийн алдааг одоо бүрэн ойлгож болно: generator дотор StopIteration шидэгдэхэд Python түүнийг RuntimeError болгон орчуулдаг бөгөөд үүнийг яг raise from-оор хийдэг. Тиймээс тэр traceback “direct cause” мөртэй байсан: эхний блок StopIteration, хоёр дахь нь “RuntimeError: generator raised StopIteration”.
Жишээ 1: from-гүйгээр — далд гинж
Хэрэв from error-ийг орхивол юу болох вэ? Python гинжийг таслахгүй, харин өөр төрлийн гинж үүсгэнэ:
python
def charge(order_id, amount):
try:
return send_request(amount)
except TimeoutError:
raise PaymentTimeoutError(f"#{order_id}: төлбөр хугацаа хэтэрлээ")Traceback (most recent call last):
File "C:\python-gunzgii\payment.py", line 19, in charge
return send_request(amount)
File "C:\python-gunzgii\payment.py", line 14, in send_request
raise TimeoutError("банкны сервер 5 секундэд хариу өгсөнгүй")
TimeoutError: банкны сервер 5 секундэд хариу өгсөнгүй
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\python-gunzgii\payment.py", line 24, in <module>
charge(1001, 50800)
File "C:\python-gunzgii\payment.py", line 21, in charge
raise PaymentTimeoutError(f"#{order_id}: төлбөр хугацаа хэтэрлээ")
PaymentTimeoutError: #1001: төлбөр хугацаа хэтэрлээХоёр блок ижил, зөвхөн холбох мөр өөр: “During handling of the above exception, another exception occurred” буюу "дээрх exception-ийг боловсруулах явцад өөр exception гарлаа". Python except блок дотор шидэгдсэн аливаа алдааг автоматаар барьж буй алдаатай холбодог. Энэ холбоог __context__ attribute-д хадгална. Мэдээлэл алдагдаагүй: хоёр алдаа хоёулаа харагдана.
Гэвч мессежийн утга өөр. “Direct cause” нь "энэ санаатай орчуулга". “During handling” нь "алдааг боловсруулж байх үед гэнэтийн зүйл болсон". Туршлагатай хөгжүүлэгч “During handling” мөрийг хараад эхлээд except блок дотор алдаа байна гэж сэжиглэнэ: зүйрлэлийн түргэн тусламжийн машин осолдсон. Тэгэхээр санаатай орчуулгад from-ийг үргэлж бичих нь кодоо уншиж буй хүнд "энэ миний зорилго" гэдгийг тодорхой хэлдэг.
Үүнийг бодит “During handling” тохиолдолтой харьцуулъя: except блок дотор санамсаргүй алдаа гаргая.
python
def charge(order_id, amount):
try:
return send_request(amount)
except TimeoutError as error:
log_failure(order_id, error)
raise PaymentTimeoutError(f"#{order_id}: төлбөр хугацаа хэтэрлээ") from errorlog_failure функц тодорхойлогдоогүй гэж бодъё. Traceback-ийн дунд мөр “During handling of the above exception, another exception occurred:” байх бөгөөд сүүлийн мөр “NameError: name ‘log_failure’ is not defined”. PaymentTimeoutError огт харагдахгүй, учир нь бидний raise мөрөнд хүрээгүй. Энэ traceback бүрэн түүхийг үнэн зөв хэлж байна: банкны сервер хариу өгөөгүй, түүнийг боловсруулах явцад бидний кодонд NameError гарсан. Python бидний алдааг нуугаагүй, анхны шалтгааныг ч алдаагүй.
Жишээ 2: from None — шалтгааныг санаатайгаар нуух
Заримдаа анхны алдаа дуудагч талд юу ч нэмэхгүй, харин будлиан үүсгэдэг. Валютын ханш хайх функцийг төсөөлье:
python
class ValidationError(ShopError):
"""Хэрэглэгчийн оруулсан утга буруу."""
RATES = {"MNT": 1, "USD": 3450, "CNY": 480}
def rate_for(currency):
try:
return RATES[currency]
except KeyError:
known = ", ".join(sorted(RATES))
raise ValidationError(f"Танигдаагүй валют '{currency}'. Боломжтой: {known}") from None
rate_for("EUR")Traceback (most recent call last):
File "C:\python-gunzgii\rates.py", line 18, in <module>
rate_for("EUR")
File "C:\python-gunzgii\rates.py", line 15, in rate_for
raise ValidationError(f"Танигдаагүй валют '{currency}'. Боломжтой: {known}") from None
ValidationError: Танигдаагүй валют 'EUR'. Боломжтой: CNY, MNT, USDfrom None нь Python-д "энэ алдааг ямар ч өмнөх алдаатай бүү холбо" гэж хэлдэг. Traceback ганц блоктой. KeyError: ‘EUR’ гэсэн доод түвшний алдаа харагдахгүй. Энэ нь зөв, учир нь тэр юу ч нэмэхгүй: ValidationError-ийн мессеж бүх мэдээллийг, тэр байтугай боломжтой сонголтуудыг, агуулж байна. KeyError бол функцийн дотоод хэрэгжилтийн нарийн ширийн зүйл: dict хэрэглэсэн нь. Хэрэв хожим ханшийг өгөгдлийн сангаас уншдаг болбол KeyError-ийн оронд өөр алдаа гарна, гэвч дуудагч тал ижил ValidationError-ийг харсаар байна.
Шударга анхааруулга: from None-ийг болгоомжтой хэрэглэ. Энэ нь мэдээллийг санаатайгаар устгадаг. Хэрэв анхны алдаа debug хийхэд хэрэгтэй мэдээлэл агуулж болох бол, жишээлбэл сүлжээний алдааны дэлгэрэнгүй, from error хэрэглэ. from None зөвхөн анхны алдаа бүрэн утгагүй, шинэ мессеж бүх зүйлийг хэлж байгаа үед. Хичээл 9.2-т бид shipping_cost-ийг .get()-ээр бичиж, энэ асуудлаас бүрмөсөн зайлсхийсэн. Энэ нь ихэвчлэн хамгийн энгийн шийдэл: хэрэв алдааг урьдчилан шалгаж болох бол except хэрэггүй.
Жишээ 3: дахин шидэх ба тэмдэглэл нэмэх
Заримдаа алдааг орчуулах шаардлагагүй, харин түүнд нэмэлт мэдээлэл хавсаргаад ижил алдааг дээш үргэлжлүүлэх хэрэгтэй. Захиалгын түвшний код төлбөрийн алдааг барьж, захиалгын мэдээллийг нэмье:
python
def place_order(order_id, customer, amount):
try:
return charge(order_id, amount)
except PaymentError as error:
error.add_note(f"Хэрэглэгч: {customer}, дүн: {amount:,}₮")
raise
place_order(1001, "Бат", 50800)Traceback-ийн төгсгөл:
PaymentTimeoutError: #1001: төлбөр хугацаа хэтэрлээ
Хэрэглэгч: Бат, дүн: 50,800₮Хоёр шинэ хэрэгсэл. add_note() бол Python 3.11-ээс хойш exception-ий method: тэмдэглэл нэмж, traceback-д мессежийн доор хэвлүүлнэ. Exception-ийн төрөл, мессеж өөрчлөгдөхгүй, ердөө нэмэлт мэдээлэл хавсарна. Энэ нь зүйрлэлийн "илгээх бичигт нэмэлт тэмдэглэл бичих": шинэ илгээх бичиг биш, хуучин дээрээ.
Ганц raise бол argument-гүй raise: "одоо барьж буй алдааг өөрчлөлтгүй дахин шид". Тэр анхны traceback-ийг бүрэн хадгална. Хичээл 6.2-ын context manager-уудын адил энэ нь "би энэ алдааг харлаа, гэхдээ шийдэх нь миний ажил биш" гэсэн мэдэгдэл. Хэрэв raise error гэж нэрээр нь дахин шидвэл ч ажиллана, гэхдээ traceback-д нэмэлт мөр орж, анхны шидэлтийн газрыг ялгахад хэцүү болж болно. Барьсан алдааг өөрчлөлтгүй дамжуулахад ганц raise нь стандарт хэлбэр.
Тэгэхээр алдаатай таарахад гурван сонголт бий. Орчуулах: raise NewError(...) from error, давхарга солигдох үед. Хавсаргах: error.add_note(...) ба raise, ижил алдаанд контекст нэмэх үед. Шийдэх: алдааг бүрэн боловсруулж, програмыг үргэлжлүүлэх, Хичээл 11.1-ийн handle шиг. Ганц сонголт байх ёсгүй: алдааг юу ч хийлгүй залгих.
Жишээ 4: гинжийг кодоор дагах
Хичээл 9.4-ийн event bus-ийн on_error функц алдааны мессежийг л хэвлэдэг байсан. Хэрэв сонсогч орчуулсан алдаа шидвэл анхны шалтгаан алдагдана. Гинжийг бүрэн дагадаг жижиг функц бичье:
python
def describe_chain(error):
lines = []
while error is not None:
lines.append(f"{type(error).__name__}: {error}")
error = error.__cause__ or error.__context__
return "\n ← ".join(lines)
try:
place_order(1001, "Бат", 50800)
except ShopError as error:
print(describe_chain(error))PaymentTimeoutError: #1001: төлбөр хугацаа хэтэрлээ
← TimeoutError: банкны сервер 5 секундэд хариу өгсөнгүйwhile loop алдаанаас эхэлж, __cause__ байвал түүнийг, үгүй бол __context__-ийг дагаж, гинжийн төгсгөл хүртэл явна. or нь Python-ий "эхнийх нь хоосон бол хоёр дахийг ав" бичлэг. Гинжийн төгсгөлд хоёулаа None болж loop зогсоно. Энэ нь Бүлэг 1-ийн давталтын санаа өгөгдлийн бүтцэд: гинжийг холбоосоор нь дагах. Ийм функц log-д нэг мөрөөр бүрэн түүхийг бичихэд, эсвэл хэрэглэгчид бус, админ самбарт алдааг харуулахад хэрэгтэй. Бүрэн traceback-ийг string болгон авах шаардлагатай бол стандарт сангийн traceback модулийн traceback.format_exception(error) гинжийг ч, тэмдэглэлүүдийг ч, мөр бүрийг ч оруулдаг.
Хүсвэл Хичээл 9.3-ын JsonLoader-ийн load() method-д json.JSONDecodeError-ийг барьж, өөрийн LoaderError-оор from error-тэйгээр орчуулж үзээрэй. Мессежид файлын замыг оруулж, хоосон JSON файл дээр туршаад гинжин traceback-ийн хоёр блокийг уншаарай. Сонирхвол Жишээ 1-ийн “from-гүй” хувилбарт error.__cause__ ба error.__context__-ийг хэвлэж, raise from-тэй хувилбартай харьцуулах нь хоёр attribute-ийн ялгааг харуулна. Мөн Хичээл 9.4-ийн event bus-ийн print_error-ийг describe_chain-ээр солих нь энэ хичээлийг өмнөх бүтээлтэй холбосон практик сайжруулалт. Эдгээр бүгд санал бөгөөд дараагийн хичээлүүд үүнийг хийсэн гэж үзэхгүй.
Гинжин traceback-ийн зөвхөн сүүлийн мөрийг унших. Мессежгүй, унших дадлын алдаа. Гинжин traceback-д сүүлийн мөр эцсийн алдааг харуулдаг, харин жинхэнэ шалтгаан ихэвчлэн эхний блокт байдаг. "Төлбөр хугацаа хэтэрлээ"-г засах гэж charge-ийг хэдэн цаг шалгасан ч асуудал банкны серверийн хаягт байж болно, эхний блок үүнийг хэлж байсан. Дүрэм: холбох мөр харагдвал дээд блокоос эхэлж, блок бүрийг доороос дээш уншиж, доош явна.
“During handling” мөрийг анзаарахгүй байх. Мессеж өөрөө зөвлөгөө. Хэрэв таны санаатай орчуулсан алдааны traceback “direct cause”-ийн оронд “During handling” харуулж байвал хоёр шалтгааны аль нэг: from-ийг мартсан, эсвэл except блок дотор санамсаргүй алдаа гарсан. Сүүлийн мөрийн алдааны нэрийг хараарай: хэрэв энэ таны шидэх гэсэн алдаа бол from-ийг нэм. Хэрэв NameError, AttributeError шиг таны хүлээгээгүй алдаа бол except блокоо шалга.
TypeError: exception causes must derive from BaseException. “Exception-ий шалтгаан BaseException-ээс удамшсан байх ёстой” гэсэн утгатай. from-ийн ард exception биш зүйл бичихэд гарна, жишээлбэл raise PaymentTimeoutError("...") from "сүлжээ тасарсан". from шалтгаан болгон exception объект эсвэл None л хүлээн авна. Шалтгааны тайлбарыг текстээр нэмэх бол add_note хэрэглэ.
RuntimeError: No active exception to reraise. "Дахин шидэх идэвхтэй exception байхгүй" гэсэн утгатай. Ганц raise-ийг except блокийн гадна бичихэд гарна: argument-гүй raise "одоо барьж буй алдааг" дахин шиддэг, гэвч except-ийн гадна барьж буй алдаа байхгүй. Ихэвчлэн догол мөрийн алдаа: raise мөр except блокоос нэг шат гадагш гарсан.
UnboundLocalError: cannot access local variable ‘error’ where it is not associated with a value. Хичээл 5.3-ын танил. except ... as error блок дуусахад Python error нэрийг устгадаг. Тэгэхээр алдааг дараа нь from-д хэрэглэх гэж блокийн гадна raise NewError() from error бичвэл энэ алдаа гарна. Шийдэл: орчуулгыг except блок дотор хийх, эсвэл Хичээл 5.3-ын загвараар алдааг тусдаа нэрэнд хадгалах.
Бодит програмд алдаа ихэвчлэн өөр алдааны үр дагавар болж гардаг бөгөөд доод түвшний алдааг өөрийн шатлалын алдаа болгон орчуулах хэрэгтэй. raise NewError(...) from error нь анхны алдааг шинэ алдааны __cause__-д хадгалж, traceback-д хоёуланг нь “The above exception was the direct cause of the following exception” мөрөөр холбож харуулдаг. Гинжин traceback-ийг уншихдаа блокууд цаг хугацааны дарааллаар, эхнийх нь анхны шалтгаан, тус бүрийг дотроо доороос дээш уншина. except блок дотор from-гүйгээр шидэгдсэн алдаа автоматаар __context__-оор холбогдож, “During handling of the above exception, another exception occurred” гэж харагдана. Энэ мөр ихэвчлэн санаандгүй алдааг, ялангуяа except блок доторхыг заадаг. from None анхны алдааг санаатайгаар нуудаг бөгөөд зөвхөн тэр юу ч нэмэхгүй үед хэрэглэгдэнэ. add_note() алдаанд тэмдэглэл хавсаргаж, ганц raise барьсан алдааг traceback-тайгаа өөрчлөлтгүй дахин шиднэ. Алдаатай таарахад орчуулах, хавсаргах, шийдэх гэсэн гурван зам бий, залгих биш. __cause__ ба __context__-ийг дагаж гинжийг кодоор уншиж болно.
Энэ бүлгийн хоёр хичээл алдааг төлөвлөх ба дамжуулахад зориулагдсан. Гурав дахь хичээл алдааны дараах цэвэрлэгээнд зориулагдана. Python-д "юу ч болсон энэ код ажиллах ёстой" гэдгийг илэрхийлэх гурван арга бий: finally блок, try-ийн else блок, мөн Бүлэг 6-ын context manager. Дараагийн хичээлд бид нэг бодит асуудлыг гурван аргаар шийдэж, тус бүрийн давуу ба сул талыг шударгаар харьцуулна. Мөн try-ийн хамгийн бага ашиглагддаг хэсэг болох else-ийн жинхэнэ утгыг нээнэ.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.