[{"data":1,"prerenderedAt":823},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-try-except-else-finally-explained":3},{"id":4,"title":5,"body":6,"description":809,"difficulty":810,"extension":811,"framework":812,"frameworkSlug":68,"meta":813,"navigation":263,"order":86,"path":814,"qaPath":815,"seo":816,"stem":817,"subtopic":818,"topic":819,"topicSlug":820,"updated":821,"__hash__":822},"blog\u002Fblog\u002Fpython-try-except-else-finally-explained.md","Python try\u002Fexcept\u002Felse\u002Ffinally Explained — Catching Exceptions the Right Way",{"type":7,"value":8,"toc":799},"minimark",[9,14,36,40,63,191,212,216,227,324,331,335,341,477,483,487,495,562,579,583,590,644,658,662,673,746,755,759,795],[10,11,13],"h2",{"id":12},"python-exception-handling-explained","Python exception handling, explained",[15,16,17,18,22,23,25,26,25,29,25,32,35],"p",{},"Exceptions are how Python signals that something went wrong. The ",[19,20,21],"code",{},"try"," statement has four\nclauses — ",[19,24,21],{},", ",[19,27,28],{},"except",[19,30,31],{},"else",[19,33,34],{},"finally"," — and knowing exactly what each does, and in\nwhat order they run, is what separates robust error handling from code that silently hides\nbugs.",[10,37,39],{"id":38},"the-four-clauses-and-their-order","The four clauses and their order",[15,41,42,44,45,47,48,50,51,55,56,58,59,62],{},[19,43,21],{}," holds the risky code. ",[19,46,28],{}," handles a matching exception. ",[19,49,31],{}," runs only if ",[52,53,54],"strong",{},"no","\nexception was raised. ",[19,57,34],{}," runs ",[52,60,61],{},"always",", exception or not.",[64,65,70],"pre",{"className":66,"code":67,"language":68,"meta":69,"style":69},"language-python shiki shiki-themes github-light github-dark","try:\n    value = int(user_input)        # might raise ValueError\nexcept ValueError:\n    print(\"not a number\")\nelse:\n    print(f\"got {value}\")          # runs only if no exception\nfinally:\n    print(\"done\")                  # always runs\n","python","",[19,71,72,84,104,114,130,137,168,175],{"__ignoreMap":69},[73,74,77,80],"span",{"class":75,"line":76},"line",1,[73,78,21],{"class":79},"szBVR",[73,81,83],{"class":82},"sVt8B",":\n",[73,85,87,90,93,97,100],{"class":75,"line":86},2,[73,88,89],{"class":82},"    value ",[73,91,92],{"class":79},"=",[73,94,96],{"class":95},"sj4cs"," int",[73,98,99],{"class":82},"(user_input)        ",[73,101,103],{"class":102},"sJ8bj","# might raise ValueError\n",[73,105,107,109,112],{"class":75,"line":106},3,[73,108,28],{"class":79},[73,110,111],{"class":95}," ValueError",[73,113,83],{"class":82},[73,115,117,120,123,127],{"class":75,"line":116},4,[73,118,119],{"class":95},"    print",[73,121,122],{"class":82},"(",[73,124,126],{"class":125},"sZZnC","\"not a number\"",[73,128,129],{"class":82},")\n",[73,131,133,135],{"class":75,"line":132},5,[73,134,31],{"class":79},[73,136,83],{"class":82},[73,138,140,142,144,147,150,153,156,159,162,165],{"class":75,"line":139},6,[73,141,119],{"class":95},[73,143,122],{"class":82},[73,145,146],{"class":79},"f",[73,148,149],{"class":125},"\"got ",[73,151,152],{"class":95},"{",[73,154,155],{"class":82},"value",[73,157,158],{"class":95},"}",[73,160,161],{"class":125},"\"",[73,163,164],{"class":82},")          ",[73,166,167],{"class":102},"# runs only if no exception\n",[73,169,171,173],{"class":75,"line":170},7,[73,172,34],{"class":79},[73,174,83],{"class":82},[73,176,178,180,182,185,188],{"class":75,"line":177},8,[73,179,119],{"class":95},[73,181,122],{"class":82},[73,183,184],{"class":125},"\"done\"",[73,186,187],{"class":82},")                  ",[73,189,190],{"class":102},"# always runs\n",[15,192,193,194,196,197,199,200,202,203,205,206,208,209,211],{},"The flow: ",[19,195,21],{}," → if it raises, a matching ",[19,198,28],{}," → otherwise ",[19,201,31],{}," → and ",[19,204,34],{}," last,\nno matter what. Putting the success-path code in ",[19,207,31],{}," keeps the ",[19,210,21],{}," block as small as\nthe operation that can actually fail.",[10,213,215],{"id":214},"catch-specific-exceptions-not-everything","Catch specific exceptions, not everything",[15,217,218,219,222,223,226],{},"A bare ",[19,220,221],{},"except:"," (or ",[19,224,225],{},"except Exception:",") catches far too much and hides real bugs. Catch\nthe narrowest exception that you can actually handle.",[64,228,230],{"className":66,"code":229,"language":68,"meta":69,"style":69},"# Bad — swallows typos, KeyboardInterrupt-adjacent bugs, everything\ntry:\n    risky()\nexcept:\n    pass\n\n# Good — only the error you expect and can recover from\ntry:\n    config = json.loads(text)\nexcept json.JSONDecodeError as e:\n    print(f\"bad config: {e}\")\n",[19,231,232,237,243,248,254,259,265,270,276,287,301],{"__ignoreMap":69},[73,233,234],{"class":75,"line":76},[73,235,236],{"class":102},"# Bad — swallows typos, KeyboardInterrupt-adjacent bugs, everything\n",[73,238,239,241],{"class":75,"line":86},[73,240,21],{"class":79},[73,242,83],{"class":82},[73,244,245],{"class":75,"line":106},[73,246,247],{"class":82},"    risky()\n",[73,249,250,252],{"class":75,"line":116},[73,251,28],{"class":79},[73,253,83],{"class":82},[73,255,256],{"class":75,"line":132},[73,257,258],{"class":79},"    pass\n",[73,260,261],{"class":75,"line":139},[73,262,264],{"emptyLinePlaceholder":263},true,"\n",[73,266,267],{"class":75,"line":170},[73,268,269],{"class":102},"# Good — only the error you expect and can recover from\n",[73,271,272,274],{"class":75,"line":177},[73,273,21],{"class":79},[73,275,83],{"class":82},[73,277,279,282,284],{"class":75,"line":278},9,[73,280,281],{"class":82},"    config ",[73,283,92],{"class":79},[73,285,286],{"class":82}," json.loads(text)\n",[73,288,290,292,295,298],{"class":75,"line":289},10,[73,291,28],{"class":79},[73,293,294],{"class":82}," json.JSONDecodeError ",[73,296,297],{"class":79},"as",[73,299,300],{"class":82}," e:\n",[73,302,304,306,308,310,313,315,318,320,322],{"class":75,"line":303},11,[73,305,119],{"class":95},[73,307,122],{"class":82},[73,309,146],{"class":79},[73,311,312],{"class":125},"\"bad config: ",[73,314,152],{"class":95},[73,316,317],{"class":82},"e",[73,319,158],{"class":95},[73,321,161],{"class":125},[73,323,129],{"class":82},[15,325,326,327,330],{},"Letting an unexpected exception propagate is usually ",[52,328,329],{},"better"," than catching it — it gives\nyou a traceback instead of a mysterious wrong result later.",[10,332,334],{"id":333},"handling-multiple-exception-types","Handling multiple exception types",[15,336,337,338,340],{},"You can list several types in one tuple, or use separate clauses when each needs different\nhandling. The first matching ",[19,339,28],{}," wins, so order from specific to general.",[64,342,344],{"className":66,"code":343,"language":68,"meta":69,"style":69},"try:\n    result = process(data)\nexcept (KeyError, IndexError) as e:\n    print(f\"missing data: {e}\")\nexcept ValueError as e:\n    print(f\"bad value: {e}\")\nexcept Exception as e:\n    print(f\"unexpected: {e}\")\n    raise                          # re-raise what you can't handle\n",[19,345,346,352,362,384,405,416,437,448,469],{"__ignoreMap":69},[73,347,348,350],{"class":75,"line":76},[73,349,21],{"class":79},[73,351,83],{"class":82},[73,353,354,357,359],{"class":75,"line":86},[73,355,356],{"class":82},"    result ",[73,358,92],{"class":79},[73,360,361],{"class":82}," process(data)\n",[73,363,364,366,369,372,374,377,380,382],{"class":75,"line":106},[73,365,28],{"class":79},[73,367,368],{"class":82}," (",[73,370,371],{"class":95},"KeyError",[73,373,25],{"class":82},[73,375,376],{"class":95},"IndexError",[73,378,379],{"class":82},") ",[73,381,297],{"class":79},[73,383,300],{"class":82},[73,385,386,388,390,392,395,397,399,401,403],{"class":75,"line":116},[73,387,119],{"class":95},[73,389,122],{"class":82},[73,391,146],{"class":79},[73,393,394],{"class":125},"\"missing data: ",[73,396,152],{"class":95},[73,398,317],{"class":82},[73,400,158],{"class":95},[73,402,161],{"class":125},[73,404,129],{"class":82},[73,406,407,409,411,414],{"class":75,"line":132},[73,408,28],{"class":79},[73,410,111],{"class":95},[73,412,413],{"class":79}," as",[73,415,300],{"class":82},[73,417,418,420,422,424,427,429,431,433,435],{"class":75,"line":139},[73,419,119],{"class":95},[73,421,122],{"class":82},[73,423,146],{"class":79},[73,425,426],{"class":125},"\"bad value: ",[73,428,152],{"class":95},[73,430,317],{"class":82},[73,432,158],{"class":95},[73,434,161],{"class":125},[73,436,129],{"class":82},[73,438,439,441,444,446],{"class":75,"line":170},[73,440,28],{"class":79},[73,442,443],{"class":95}," Exception",[73,445,413],{"class":79},[73,447,300],{"class":82},[73,449,450,452,454,456,459,461,463,465,467],{"class":75,"line":177},[73,451,119],{"class":95},[73,453,122],{"class":82},[73,455,146],{"class":79},[73,457,458],{"class":125},"\"unexpected: ",[73,460,152],{"class":95},[73,462,317],{"class":82},[73,464,158],{"class":95},[73,466,161],{"class":125},[73,468,129],{"class":82},[73,470,471,474],{"class":75,"line":278},[73,472,473],{"class":79},"    raise",[73,475,476],{"class":102},"                          # re-raise what you can't handle\n",[15,478,479,480,482],{},"Because subclasses match parent clauses, a more general ",[19,481,28],{}," placed first would shadow\nthe specific ones below it.",[10,484,486],{"id":485},"finally-always-runs-even-on-return","finally always runs — even on return",[15,488,489,491,492,494],{},[19,490,34],{}," executes even if the ",[19,493,21],{}," block returns, breaks, or raises. That makes it the\nplace for cleanup that must happen no matter what (though context managers are usually\ncleaner).",[64,496,498],{"className":66,"code":497,"language":68,"meta":69,"style":69},"def read():\n    f = open(\"data.txt\")\n    try:\n        return f.read()            # finally still runs before the return completes\n    finally:\n        f.close()                  # guaranteed, even on exception\n",[19,499,500,512,529,536,547,554],{"__ignoreMap":69},[73,501,502,505,509],{"class":75,"line":76},[73,503,504],{"class":79},"def",[73,506,508],{"class":507},"sScJk"," read",[73,510,511],{"class":82},"():\n",[73,513,514,517,519,522,524,527],{"class":75,"line":86},[73,515,516],{"class":82},"    f ",[73,518,92],{"class":79},[73,520,521],{"class":95}," open",[73,523,122],{"class":82},[73,525,526],{"class":125},"\"data.txt\"",[73,528,129],{"class":82},[73,530,531,534],{"class":75,"line":106},[73,532,533],{"class":79},"    try",[73,535,83],{"class":82},[73,537,538,541,544],{"class":75,"line":116},[73,539,540],{"class":79},"        return",[73,542,543],{"class":82}," f.read()            ",[73,545,546],{"class":102},"# finally still runs before the return completes\n",[73,548,549,552],{"class":75,"line":132},[73,550,551],{"class":79},"    finally",[73,553,83],{"class":82},[73,555,556,559],{"class":75,"line":139},[73,557,558],{"class":82},"        f.close()                  ",[73,560,561],{"class":102},"# guaranteed, even on exception\n",[15,563,564,565,568,569,571,572,575,576,578],{},"A subtle trap: a ",[19,566,567],{},"return"," inside ",[19,570,34],{}," will ",[52,573,574],{},"override"," any return or exception from\nthe ",[19,577,21],{}," block — avoid it.",[10,580,582],{"id":581},"exception-chaining-with-raise-from","Exception chaining with raise from",[15,584,585,586,589],{},"When you catch one error and raise another, use ",[19,587,588],{},"raise ... from"," to preserve the original\ncause. This keeps the full story in the traceback (\"during handling of the above, another\noccurred\").",[64,591,593],{"className":66,"code":592,"language":68,"meta":69,"style":69},"try:\n    config = load(path)\nexcept FileNotFoundError as e:\n    raise RuntimeError(\"config missing\") from e   # chains the cause\n",[19,594,595,601,610,621],{"__ignoreMap":69},[73,596,597,599],{"class":75,"line":76},[73,598,21],{"class":79},[73,600,83],{"class":82},[73,602,603,605,607],{"class":75,"line":86},[73,604,281],{"class":82},[73,606,92],{"class":79},[73,608,609],{"class":82}," load(path)\n",[73,611,612,614,617,619],{"class":75,"line":106},[73,613,28],{"class":79},[73,615,616],{"class":95}," FileNotFoundError",[73,618,413],{"class":79},[73,620,300],{"class":82},[73,622,623,625,628,630,633,635,638,641],{"class":75,"line":116},[73,624,473],{"class":79},[73,626,627],{"class":95}," RuntimeError",[73,629,122],{"class":82},[73,631,632],{"class":125},"\"config missing\"",[73,634,379],{"class":82},[73,636,637],{"class":79},"from",[73,639,640],{"class":82}," e   ",[73,642,643],{"class":102},"# chains the cause\n",[15,645,646,647,649,650,653,654,657],{},"Without ",[19,648,637],{},", Python still shows the implicit context, but ",[19,651,652],{},"from e"," states the\nrelationship explicitly. Use ",[19,655,656],{},"from None"," to deliberately suppress a noisy original cause.",[10,659,661],{"id":660},"accessing-exception-details","Accessing exception details",[15,663,664,665,668,669,672],{},"The ",[19,666,667],{},"as e"," binding gives you the exception object. You can read its ",[19,670,671],{},"args",", its message, and\n(3.11+) attach notes for richer diagnostics.",[64,674,676],{"className":66,"code":675,"language":68,"meta":69,"style":69},"try:\n    int(\"abc\")\nexcept ValueError as e:\n    print(type(e).__name__, e)     # ValueError invalid literal for int()...\n    e.add_note(\"while parsing user input\")   # 3.11+\n    raise\n",[19,677,678,684,696,706,727,741],{"__ignoreMap":69},[73,679,680,682],{"class":75,"line":76},[73,681,21],{"class":79},[73,683,83],{"class":82},[73,685,686,689,691,694],{"class":75,"line":86},[73,687,688],{"class":95},"    int",[73,690,122],{"class":82},[73,692,693],{"class":125},"\"abc\"",[73,695,129],{"class":82},[73,697,698,700,702,704],{"class":75,"line":106},[73,699,28],{"class":79},[73,701,111],{"class":95},[73,703,413],{"class":79},[73,705,300],{"class":82},[73,707,708,710,712,715,718,721,724],{"class":75,"line":116},[73,709,119],{"class":95},[73,711,122],{"class":82},[73,713,714],{"class":95},"type",[73,716,717],{"class":82},"(e).",[73,719,720],{"class":95},"__name__",[73,722,723],{"class":82},", e)     ",[73,725,726],{"class":102},"# ValueError invalid literal for int()...\n",[73,728,729,732,735,738],{"class":75,"line":132},[73,730,731],{"class":82},"    e.add_note(",[73,733,734],{"class":125},"\"while parsing user input\"",[73,736,737],{"class":82},")   ",[73,739,740],{"class":102},"# 3.11+\n",[73,742,743],{"class":75,"line":139},[73,744,745],{"class":79},"    raise\n",[15,747,748,749,751,752,754],{},"Note that ",[19,750,317],{}," is deleted at the end of the ",[19,753,28],{}," block, so assign it to another name if\nyou need it afterwards.",[10,756,758],{"id":757},"recap","Recap",[15,760,761,763,764,763,766,763,768,770,771,774,775,778,779,781,782,784,785,787,788,791,792,794],{},[19,762,21],{},"\u002F",[19,765,28],{},[19,767,31],{},[19,769,34],{},": risky code, the handler, the no-exception path, and the\nalways-runs cleanup — in that order. Catch the ",[52,772,773],{},"most specific"," exception you can actually\nhandle and let the rest propagate so you keep real tracebacks; never use a bare ",[19,776,777],{},"except: pass",". ",[19,780,34],{}," runs even through ",[19,783,567],{}," and exceptions (but don't ",[19,786,567],{}," inside it).\nUse ",[19,789,790],{},"raise NewError(...) from original"," to chain causes, and the ",[19,793,667],{}," binding to inspect\ndetails. Good error handling is narrow, intentional, and never silent.",[796,797,798],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":69,"searchDepth":86,"depth":86,"links":800},[801,802,803,804,805,806,807,808],{"id":12,"depth":86,"text":13},{"id":38,"depth":86,"text":39},{"id":214,"depth":86,"text":215},{"id":333,"depth":86,"text":334},{"id":485,"depth":86,"text":486},{"id":581,"depth":86,"text":582},{"id":660,"depth":86,"text":661},{"id":757,"depth":86,"text":758},"How Python exception handling works — the full try\u002Fexcept\u002Felse\u002Ffinally structure, catching specific exceptions, exception chaining with raise from, and the patterns that avoid swallowing bugs.","medium","md","Python",{},"\u002Fblog\u002Fpython-try-except-else-finally-explained","\u002Fpython\u002Fexceptions\u002Ftry-except",{"title":5,"description":809},"blog\u002Fpython-try-except-else-finally-explained","try \u002F except \u002F else \u002F finally","Errors & Exceptions","exceptions","2026-06-19","BHLvj8DiFmJgn7aXrUJRkzWPZNg2MKcNpR4IXOeaVt0",1782244093109]