[{"data":1,"prerenderedAt":858},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-context-managers-with-explained":3},{"id":4,"title":5,"body":6,"description":844,"difficulty":845,"extension":846,"framework":847,"frameworkSlug":59,"meta":848,"navigation":255,"order":67,"path":849,"qaPath":850,"seo":851,"stem":852,"subtopic":853,"topic":854,"topicSlug":855,"updated":856,"__hash__":857},"blog\u002Fblog\u002Fpython-context-managers-with-explained.md","Python Context Managers and the with Statement Explained",{"type":7,"value":8,"toc":832},"minimark",[9,14,27,31,54,114,130,141,159,290,300,306,323,423,437,441,462,617,636,640,650,704,711,715,734,775,782,786,828],[10,11,13],"h2",{"id":12},"python-context-managers-explained","Python context managers, explained",[15,16,17,21,22,26],"p",{},[18,19,20],"code",{},"with open(...) as f:"," is the first context manager every Python developer meets, but the\npattern goes far beyond files. A context manager guarantees that ",[23,24,25],"strong",{},"setup and teardown\nhappen reliably",", even when an exception is raised — which is why interviewers use it to\nprobe your understanding of resource management and the protocol underneath. This guide\ncovers both ways to build one and the exception-handling subtleties.",[10,28,30],{"id":29},"what-the-with-statement-does","What the with statement does",[15,32,33,34,37,38,41,42,45,46,49,50,53],{},"A ",[18,35,36],{},"with"," block calls an object's ",[18,39,40],{},"__enter__"," on the way in and its ",[18,43,44],{},"__exit__"," on the way\nout — ",[23,47,48],{},"guaranteed",", whether the block finishes normally, returns, or raises. It's\nstructured cleanup without a manual ",[18,51,52],{},"try\u002Ffinally",".",[55,56,61],"pre",{"className":57,"code":58,"language":59,"meta":60,"style":60},"language-python shiki shiki-themes github-light github-dark","with open(\"data.txt\") as f:     # __enter__ runs, returns the file\n    data = f.read()\n# __exit__ runs here no matter what — the file is closed\n","python","",[18,62,63,96,108],{"__ignoreMap":60},[64,65,68,71,75,79,83,86,89,92],"span",{"class":66,"line":67},"line",1,[64,69,36],{"class":70},"szBVR",[64,72,74],{"class":73},"sj4cs"," open",[64,76,78],{"class":77},"sVt8B","(",[64,80,82],{"class":81},"sZZnC","\"data.txt\"",[64,84,85],{"class":77},") ",[64,87,88],{"class":70},"as",[64,90,91],{"class":77}," f:     ",[64,93,95],{"class":94},"sJ8bj","# __enter__ runs, returns the file\n",[64,97,99,102,105],{"class":66,"line":98},2,[64,100,101],{"class":77},"    data ",[64,103,104],{"class":70},"=",[64,106,107],{"class":77}," f.read()\n",[64,109,111],{"class":66,"line":110},3,[64,112,113],{"class":94},"# __exit__ runs here no matter what — the file is closed\n",[15,115,116,117,119,120,122,123,125,126,129],{},"The value after ",[18,118,88],{}," is whatever ",[18,121,40],{}," returns. The win over ",[18,124,52],{}," is that\nthe cleanup logic lives ",[23,127,128],{},"with the resource",", not scattered around every use site.",[10,131,133,134,137,138],{"id":132},"the-protocol-enter-and-exit","The protocol: ",[23,135,136],{},"enter"," and ",[23,139,140],{},"exit",[15,142,143,144,137,146,148,149,151,152,154,155,158],{},"Any object implementing ",[18,145,40],{},[18,147,44],{}," is a context manager. ",[18,150,40],{}," does\nsetup and returns the value bound by ",[18,153,88],{},"; ",[18,156,157],{},"__exit__(exc_type, exc_val, exc_tb)"," does\nteardown and receives details of any exception that occurred.",[55,160,162],{"className":57,"code":161,"language":59,"meta":60,"style":60},"class Resource:\n    def __enter__(self):\n        print(\"acquire\")\n        return self                # bound to the `as` variable\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        print(\"release\")           # always runs\n        return False               # don't suppress exceptions\n\nwith Resource() as r:\n    print(\"using\", r)\n# acquire \u002F using \u002F release\n",[18,163,164,176,187,200,212,223,239,250,257,270,284],{"__ignoreMap":60},[64,165,166,169,173],{"class":66,"line":67},[64,167,168],{"class":70},"class",[64,170,172],{"class":171},"sScJk"," Resource",[64,174,175],{"class":77},":\n",[64,177,178,181,184],{"class":66,"line":98},[64,179,180],{"class":70},"    def",[64,182,183],{"class":73}," __enter__",[64,185,186],{"class":77},"(self):\n",[64,188,189,192,194,197],{"class":66,"line":110},[64,190,191],{"class":73},"        print",[64,193,78],{"class":77},[64,195,196],{"class":81},"\"acquire\"",[64,198,199],{"class":77},")\n",[64,201,203,206,209],{"class":66,"line":202},4,[64,204,205],{"class":70},"        return",[64,207,208],{"class":73}," self",[64,210,211],{"class":94},"                # bound to the `as` variable\n",[64,213,215,217,220],{"class":66,"line":214},5,[64,216,180],{"class":70},[64,218,219],{"class":73}," __exit__",[64,221,222],{"class":77},"(self, exc_type, exc_val, exc_tb):\n",[64,224,226,228,230,233,236],{"class":66,"line":225},6,[64,227,191],{"class":73},[64,229,78],{"class":77},[64,231,232],{"class":81},"\"release\"",[64,234,235],{"class":77},")           ",[64,237,238],{"class":94},"# always runs\n",[64,240,242,244,247],{"class":66,"line":241},7,[64,243,205],{"class":70},[64,245,246],{"class":73}," False",[64,248,249],{"class":94},"               # don't suppress exceptions\n",[64,251,253],{"class":66,"line":252},8,[64,254,256],{"emptyLinePlaceholder":255},true,"\n",[64,258,260,262,265,267],{"class":66,"line":259},9,[64,261,36],{"class":70},[64,263,264],{"class":77}," Resource() ",[64,266,88],{"class":70},[64,268,269],{"class":77}," r:\n",[64,271,273,276,278,281],{"class":66,"line":272},10,[64,274,275],{"class":73},"    print",[64,277,78],{"class":77},[64,279,280],{"class":81},"\"using\"",[64,282,283],{"class":77},", r)\n",[64,285,287],{"class":66,"line":286},11,[64,288,289],{"class":94},"# acquire \u002F using \u002F release\n",[15,291,292,293,296,297,53],{},"If the block raised, the three ",[18,294,295],{},"exc_*"," arguments describe it; if it exited cleanly, they're\nall ",[18,298,299],{},"None",[10,301,303,304],{"id":302},"handling-exceptions-in-exit","Handling exceptions in ",[23,305,140],{},[15,307,308,310,311,314,315,318,319,322],{},[18,309,44],{}," is where the resource-management subtlety lives. Its ",[23,312,313],{},"return value decides\nwhether the exception propagates",": return a falsy value (the default) and the exception\nre-raises after cleanup; return ",[18,316,317],{},"True"," and you ",[23,320,321],{},"suppress"," it.",[55,324,326],{"className":57,"code":325,"language":59,"meta":60,"style":60},"class Suppress:\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        if exc_type is ValueError:\n            print(\"swallowing\", exc_val)\n            return True            # suppress ValueError only\n        return False               # let everything else propagate\n\nwith Suppress():\n    raise ValueError(\"boom\")       # swallowed; program continues\n",[18,327,328,337,345,361,374,385,394,398,405],{"__ignoreMap":60},[64,329,330,332,335],{"class":66,"line":67},[64,331,168],{"class":70},[64,333,334],{"class":171}," Suppress",[64,336,175],{"class":77},[64,338,339,341,343],{"class":66,"line":98},[64,340,180],{"class":70},[64,342,219],{"class":73},[64,344,222],{"class":77},[64,346,347,350,353,356,359],{"class":66,"line":110},[64,348,349],{"class":70},"        if",[64,351,352],{"class":77}," exc_type ",[64,354,355],{"class":70},"is",[64,357,358],{"class":73}," ValueError",[64,360,175],{"class":77},[64,362,363,366,368,371],{"class":66,"line":202},[64,364,365],{"class":73},"            print",[64,367,78],{"class":77},[64,369,370],{"class":81},"\"swallowing\"",[64,372,373],{"class":77},", exc_val)\n",[64,375,376,379,382],{"class":66,"line":214},[64,377,378],{"class":70},"            return",[64,380,381],{"class":73}," True",[64,383,384],{"class":94},"            # suppress ValueError only\n",[64,386,387,389,391],{"class":66,"line":225},[64,388,205],{"class":70},[64,390,246],{"class":73},[64,392,393],{"class":94},"               # let everything else propagate\n",[64,395,396],{"class":66,"line":241},[64,397,256],{"emptyLinePlaceholder":255},[64,399,400,402],{"class":66,"line":252},[64,401,36],{"class":70},[64,403,404],{"class":77}," Suppress():\n",[64,406,407,410,412,414,417,420],{"class":66,"line":259},[64,408,409],{"class":70},"    raise",[64,411,358],{"class":73},[64,413,78],{"class":77},[64,415,416],{"class":81},"\"boom\"",[64,418,419],{"class":77},")       ",[64,421,422],{"class":94},"# swallowed; program continues\n",[15,424,425,426,432,433,436],{},"The trap: an ",[23,427,428,429],{},"accidental ",[18,430,431],{},"return True"," silently hides every error. Default to returning\n",[18,434,435],{},"False"," (or nothing) unless suppression is genuinely intended.",[10,438,440],{"id":439},"the-easy-way-contextlibcontextmanager","The easy way: contextlib.contextmanager",[15,442,443,444,447,448,451,452,455,456,458,459,461],{},"For simple cases, writing a whole class is overkill. The ",[18,445,446],{},"@contextmanager"," decorator turns\na ",[23,449,450],{},"generator"," into a context manager: everything before ",[18,453,454],{},"yield"," is setup, the yielded\nvalue is the ",[18,457,88],{}," target, and everything after ",[18,460,454],{}," is teardown.",[55,463,465],{"className":57,"code":464,"language":59,"meta":60,"style":60},"from contextlib import contextmanager\n\n@contextmanager\ndef timer(label):\n    import time\n    start = time.perf_counter()           # setup\n    try:\n        yield                             # the with-block runs here\n    finally:\n        print(f\"{label}: {time.perf_counter() - start:.4f}s\")   # teardown\n\nwith timer(\"query\"):\n    run_query()\n",[18,466,467,481,485,490,501,509,522,529,537,544,593,597,611],{"__ignoreMap":60},[64,468,469,472,475,478],{"class":66,"line":67},[64,470,471],{"class":70},"from",[64,473,474],{"class":77}," contextlib ",[64,476,477],{"class":70},"import",[64,479,480],{"class":77}," contextmanager\n",[64,482,483],{"class":66,"line":98},[64,484,256],{"emptyLinePlaceholder":255},[64,486,487],{"class":66,"line":110},[64,488,489],{"class":171},"@contextmanager\n",[64,491,492,495,498],{"class":66,"line":202},[64,493,494],{"class":70},"def",[64,496,497],{"class":171}," timer",[64,499,500],{"class":77},"(label):\n",[64,502,503,506],{"class":66,"line":214},[64,504,505],{"class":70},"    import",[64,507,508],{"class":77}," time\n",[64,510,511,514,516,519],{"class":66,"line":225},[64,512,513],{"class":77},"    start ",[64,515,104],{"class":70},[64,517,518],{"class":77}," time.perf_counter()           ",[64,520,521],{"class":94},"# setup\n",[64,523,524,527],{"class":66,"line":241},[64,525,526],{"class":70},"    try",[64,528,175],{"class":77},[64,530,531,534],{"class":66,"line":252},[64,532,533],{"class":70},"        yield",[64,535,536],{"class":94},"                             # the with-block runs here\n",[64,538,539,542],{"class":66,"line":259},[64,540,541],{"class":70},"    finally",[64,543,175],{"class":77},[64,545,546,548,550,553,556,559,562,565,568,570,573,576,579,582,584,587,590],{"class":66,"line":272},[64,547,191],{"class":73},[64,549,78],{"class":77},[64,551,552],{"class":70},"f",[64,554,555],{"class":81},"\"",[64,557,558],{"class":73},"{",[64,560,561],{"class":77},"label",[64,563,564],{"class":73},"}",[64,566,567],{"class":81},": ",[64,569,558],{"class":73},[64,571,572],{"class":77},"time.perf_counter() ",[64,574,575],{"class":70},"-",[64,577,578],{"class":77}," start",[64,580,581],{"class":70},":.4f",[64,583,564],{"class":73},[64,585,586],{"class":81},"s\"",[64,588,589],{"class":77},")   ",[64,591,592],{"class":94},"# teardown\n",[64,594,595],{"class":66,"line":286},[64,596,256],{"emptyLinePlaceholder":255},[64,598,600,602,605,608],{"class":66,"line":599},12,[64,601,36],{"class":70},[64,603,604],{"class":77}," timer(",[64,606,607],{"class":81},"\"query\"",[64,609,610],{"class":77},"):\n",[64,612,614],{"class":66,"line":613},13,[64,615,616],{"class":77},"    run_query()\n",[15,618,619,620,622,623,625,626,631,632,635],{},"The ",[18,621,52],{}," around ",[18,624,454],{}," is what makes teardown run even on exception — the\nexception is re-raised ",[23,627,628,629],{},"at the ",[18,630,454],{}," inside the generator, so ",[18,633,634],{},"finally"," catches it.",[10,637,639],{"id":638},"managing-multiple-resources","Managing multiple resources",[15,641,642,643,645,646,649],{},"You can open several context managers in one ",[18,644,36],{},", and they're entered left-to-right and\nexited in ",[23,647,648],{},"reverse"," — so dependent resources tear down in the right order.",[55,651,653],{"className":57,"code":652,"language":59,"meta":60,"style":60},"with open(\"in.txt\") as src, open(\"out.txt\", \"w\") as dst:\n    dst.write(src.read())\n# dst closes first, then src\n",[18,654,655,694,699],{"__ignoreMap":60},[64,656,657,659,661,663,666,668,670,673,676,678,681,684,687,689,691],{"class":66,"line":67},[64,658,36],{"class":70},[64,660,74],{"class":73},[64,662,78],{"class":77},[64,664,665],{"class":81},"\"in.txt\"",[64,667,85],{"class":77},[64,669,88],{"class":70},[64,671,672],{"class":77}," src, ",[64,674,675],{"class":73},"open",[64,677,78],{"class":77},[64,679,680],{"class":81},"\"out.txt\"",[64,682,683],{"class":77},", ",[64,685,686],{"class":81},"\"w\"",[64,688,85],{"class":77},[64,690,88],{"class":70},[64,692,693],{"class":77}," dst:\n",[64,695,696],{"class":66,"line":98},[64,697,698],{"class":77},"    dst.write(src.read())\n",[64,700,701],{"class":66,"line":110},[64,702,703],{"class":94},"# dst closes first, then src\n",[15,705,706,707,710],{},"For a dynamic or unknown number of resources, ",[18,708,709],{},"contextlib.ExitStack"," lets you enter context\nmanagers in a loop and guarantees they all close.",[10,712,714],{"id":713},"where-context-managers-earn-their-keep","Where context managers earn their keep",[15,716,717,718,721,722,725,726,729,730,733],{},"Anywhere there's a paired acquire\u002Frelease: ",[23,719,720],{},"files"," (close), ",[23,723,724],{},"locks","\n(",[18,727,728],{},"with lock:"," acquire\u002Frelease), ",[23,731,732],{},"database connections\u002Ftransactions"," (commit or rollback),\ntemporary directories, and patching in tests.",[55,735,737],{"className":57,"code":736,"language":59,"meta":60,"style":60},"import threading\nlock = threading.Lock()\n\nwith lock:                 # __enter__ acquires, __exit__ releases — even on error\n    update_shared_state()\n",[18,738,739,746,756,760,770],{"__ignoreMap":60},[64,740,741,743],{"class":66,"line":67},[64,742,477],{"class":70},[64,744,745],{"class":77}," threading\n",[64,747,748,751,753],{"class":66,"line":98},[64,749,750],{"class":77},"lock ",[64,752,104],{"class":70},[64,754,755],{"class":77}," threading.Lock()\n",[64,757,758],{"class":66,"line":110},[64,759,256],{"emptyLinePlaceholder":255},[64,761,762,764,767],{"class":66,"line":202},[64,763,36],{"class":70},[64,765,766],{"class":77}," lock:                 ",[64,768,769],{"class":94},"# __enter__ acquires, __exit__ releases — even on error\n",[64,771,772],{"class":66,"line":214},[64,773,774],{"class":77},"    update_shared_state()\n",[15,776,777,778,781],{},"The guarantee that release happens ",[23,779,780],{},"even when the body raises"," is exactly why locks and\ntransactions use this pattern.",[10,783,785],{"id":784},"recap","Recap",[15,787,788,789,794,795,800,801,803,804,806,807,809,810,813,814,622,816,818,819,822,823,825,826,53],{},"A context manager pairs ",[23,790,791,793],{},[18,792,40],{}," (setup)"," with ",[23,796,797,799],{},[18,798,44],{}," (teardown)",", and the\n",[18,802,36],{}," statement guarantees teardown runs even on exceptions. ",[18,805,44],{},"'s return value\ncontrols propagation — falsy re-raises (the safe default), ",[18,808,317],{}," suppresses. For simple\ncases, ",[18,811,812],{},"@contextlib.contextmanager"," turns a generator into a context manager with a\n",[18,815,52],{},[18,817,454],{},". Multiple managers exit in reverse order, and ",[18,820,821],{},"ExitStack","\nhandles dynamic sets. Reach for ",[18,824,36],{}," whenever a resource must be released no matter what\n— it's cleaner and safer than hand-rolled ",[18,827,52],{},[829,830,831],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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":60,"searchDepth":98,"depth":98,"links":833},[834,835,836,838,840,841,842,843],{"id":12,"depth":98,"text":13},{"id":29,"depth":98,"text":30},{"id":132,"depth":98,"text":837},"The protocol: enter and exit",{"id":302,"depth":98,"text":839},"Handling exceptions in exit",{"id":439,"depth":98,"text":440},{"id":638,"depth":98,"text":639},{"id":713,"depth":98,"text":714},{"id":784,"depth":98,"text":785},"How Python context managers and the with statement work — __enter__ and __exit__, contextlib.contextmanager, exception handling in __exit__, and managing multiple resources.","medium","md","Python",{},"\u002Fblog\u002Fpython-context-managers-with-explained","\u002Fpython\u002Fexceptions\u002Fcontext-managers",{"title":5,"description":844},"blog\u002Fpython-context-managers-with-explained","Context Managers & with","Errors & Exceptions","exceptions","2026-06-19","T0jxO23KCCJnQKHBEMqJyyx5LIrewAe06qYA9qyjipk",1781808673080]