[{"data":1,"prerenderedAt":2050},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only":2042},{"id":4,"title":5,"body":6,"dateModified":2008,"datePublished":2008,"description":2009,"extension":2010,"faq":2011,"meta":2024,"navigation":229,"path":2035,"seo":2036,"slug":2038,"stem":2039,"type":2040,"__hash__":2041},"docs\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002Findex.md","Read Formula Results with openpyxl data_only",{"type":7,"value":8,"toc":1993},"minimark",[9,36,155,160,187,194,198,201,388,399,403,412,754,765,877,881,888,1096,1109,1113,1116,1388,1391,1395,1398,1412,1493,1496,1589,1593,1596,1645,1648,1652,1737,1746,1750,1854,1858,1873,1877,1885,1889,1902,1916,1925,1934,1940,1944,1947,1956,1959,1989],[10,11,12,16,17,20,21,24,25,29,30,35],"p",{},[13,14,15],"code",{},"load_workbook(path, data_only=True)"," promises the values behind your formulas and then, for a freshly generated file, hands back a column of ",[13,18,19],{},"None",". Nothing is broken: ",[13,22,23],{},"data_only"," reads a ",[26,27,28],"em",{},"cache"," written by whichever spreadsheet application last saved the file. This guide, part of ",[31,32,34],"a",{"href":33},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002F","Working with Excel Formulas in Python",", explains where that cache comes from, how to detect that it is missing, and what to do in each situation.",[37,38,46,47,46,51,46,55,46,62,46,72,46,79,46,84,46,89,46,94,46,99,46,101,46,105,46,112,46,117,46,119,46,122,46,129,46,134,46,139,46,143,46,147,46,150],"svg",{"viewBox":39,"role":40,"ariaLabelledBy":41,"xmlns":44,"style":45},"0 0 760 262","img",[42,43],"do-cache-t","do-cache-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[48,49,50],"title",{"id":42},"Where a cached formula value comes from",[52,53,54],"desc",{"id":43},"Two paths into the same file. A workbook written by Python holds only formula text, so data_only returns None. A workbook opened and saved by Excel holds both the formula and the number Excel calculated, so data_only returns that number.",[56,57],"rect",{"x":58,"y":58,"width":59,"height":60,"fill":61},"0","760","262","#ffffff",[56,63],{"x":64,"y":65,"width":66,"height":67,"rx":68,"fill":69,"stroke":70,"style":71},"24","28","300","96","14","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[73,74,78],"text",{"x":75,"y":76,"style":77},"174","56","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Path A — Python wrote it",[73,80,83],{"x":75,"y":81,"style":82},"80","font-size:12px;fill:var(--muted,#5b6780);text-anchor:middle","cell holds: \"=SUM(D2:D9)\"",[73,85,88],{"x":75,"y":86,"style":87},"102","font-size:12px;font-weight:700;fill:var(--danger,#dc2626);text-anchor:middle","cache slot: empty",[56,90],{"x":91,"y":65,"width":66,"height":67,"rx":68,"fill":92,"stroke":93,"style":71},"436","#d9f4f1","var(--teal,#0f9488)",[73,95,98],{"x":96,"y":76,"style":97},"586","font-size:13px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Path B — Excel saved it",[73,100,83],{"x":96,"y":81,"style":82},[73,102,104],{"x":96,"y":86,"style":103},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","cache slot: 1284.60",[106,107],"line",{"x1":75,"y1":108,"x2":75,"y2":109,"stroke":110,"style":111},"128","166","var(--muted,#5b6780)","stroke-width:1.5px",[113,114],"polygon",{"points":115,"fill":116},"174,170 168,158 180,158","#5b6780",[106,118],{"x1":96,"y1":108,"x2":96,"y2":109,"stroke":110,"style":111},[113,120],{"points":121,"fill":116},"586,170 580,158 592,158",[56,123],{"x":64,"y":124,"width":66,"height":125,"rx":126,"fill":127,"stroke":128},"172","66","12","#fce9e9","var(--danger,#dc2626)",[73,130,133],{"x":75,"y":131,"style":132},"198","font-size:12.5px;font-weight:700;fill:var(--danger,#dc2626);text-anchor:middle","data_only=True → None",[73,135,138],{"x":75,"y":136,"style":137},"222","font-size:11.5px;fill:var(--muted,#5b6780);text-anchor:middle","nothing has calculated anything yet",[56,140],{"x":91,"y":124,"width":66,"height":125,"rx":126,"fill":141,"stroke":142},"#ebebfd","var(--line,#cdd5e6)",[73,144,146],{"x":96,"y":131,"style":145},"font-size:12.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","data_only=True → 1284.6",[73,148,149],{"x":96,"y":136,"style":137},"the number Excel stored on save",[73,151,154],{"x":152,"y":153,"style":82},"380","152","same file, same code",[156,157,159],"h2",{"id":158},"prerequisites","Prerequisites",[161,162,167],"pre",{"className":163,"code":164,"language":165,"meta":166,"style":166},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pandas\n","bash","",[13,168,169],{"__ignoreMap":166},[170,171,173,177,181,184],"span",{"class":106,"line":172},1,[170,174,176],{"class":175},"sMTad","pip",[170,178,180],{"class":179},"srMev"," install",[170,182,183],{"class":179}," openpyxl",[170,185,186],{"class":179}," pandas\n",[10,188,189,190,193],{},"The ",[13,191,192],{},"pandas"," install is only needed for the recompute-in-Python option in the last section.",[156,195,197],{"id":196},"reproduce-the-none-in-ten-lines","Reproduce the None in ten lines",[10,199,200],{},"Seeing it happen makes the rule stick:",[161,202,206],{"className":203,"code":204,"language":205,"meta":166,"style":166},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook, load_workbook\n\nwb = Workbook()\nws = wb.active\nws.append([\"Item\", \"Qty\", \"Price\", \"Total\"])\nws.append([\"A-100\", 4, 19.99, \"=B2*C2\"])\nwb.save(\"fresh.xlsx\")\n\nprint(load_workbook(\"fresh.xlsx\")[\"Sheet\"][\"D2\"].value)                  # '=B2*C2'\nprint(load_workbook(\"fresh.xlsx\", data_only=True)[\"Sheet\"][\"D2\"].value)  # None\n","python",[13,207,208,224,231,243,254,282,308,320,325,355],{"__ignoreMap":166},[170,209,210,214,218,221],{"class":106,"line":172},[170,211,213],{"class":212},"s-kum","from",[170,215,217],{"class":216},"skGVy"," openpyxl ",[170,219,220],{"class":212},"import",[170,222,223],{"class":216}," Workbook, load_workbook\n",[170,225,227],{"class":106,"line":226},2,[170,228,230],{"emptyLinePlaceholder":229},true,"\n",[170,232,234,237,240],{"class":106,"line":233},3,[170,235,236],{"class":216},"wb ",[170,238,239],{"class":212},"=",[170,241,242],{"class":216}," Workbook()\n",[170,244,246,249,251],{"class":106,"line":245},4,[170,247,248],{"class":216},"ws ",[170,250,239],{"class":212},[170,252,253],{"class":216}," wb.active\n",[170,255,257,260,263,266,269,271,274,276,279],{"class":106,"line":256},5,[170,258,259],{"class":216},"ws.append([",[170,261,262],{"class":179},"\"Item\"",[170,264,265],{"class":216},", ",[170,267,268],{"class":179},"\"Qty\"",[170,270,265],{"class":216},[170,272,273],{"class":179},"\"Price\"",[170,275,265],{"class":216},[170,277,278],{"class":179},"\"Total\"",[170,280,281],{"class":216},"])\n",[170,283,285,287,290,292,296,298,301,303,306],{"class":106,"line":284},6,[170,286,259],{"class":216},[170,288,289],{"class":179},"\"A-100\"",[170,291,265],{"class":216},[170,293,295],{"class":294},"sP0c6","4",[170,297,265],{"class":216},[170,299,300],{"class":294},"19.99",[170,302,265],{"class":216},[170,304,305],{"class":179},"\"=B2*C2\"",[170,307,281],{"class":216},[170,309,311,314,317],{"class":106,"line":310},7,[170,312,313],{"class":216},"wb.save(",[170,315,316],{"class":179},"\"fresh.xlsx\"",[170,318,319],{"class":216},")\n",[170,321,323],{"class":106,"line":322},8,[170,324,230],{"emptyLinePlaceholder":229},[170,326,328,331,334,336,339,342,345,348,351],{"class":106,"line":327},9,[170,329,330],{"class":294},"print",[170,332,333],{"class":216},"(load_workbook(",[170,335,316],{"class":179},[170,337,338],{"class":216},")[",[170,340,341],{"class":179},"\"Sheet\"",[170,343,344],{"class":216},"][",[170,346,347],{"class":179},"\"D2\"",[170,349,350],{"class":216},"].value)                  ",[170,352,354],{"class":353},"s-wDw","# '=B2*C2'\n",[170,356,358,360,362,364,366,369,371,374,376,378,380,382,385],{"class":106,"line":357},10,[170,359,330],{"class":294},[170,361,333],{"class":216},[170,363,316],{"class":179},[170,365,265],{"class":216},[170,367,23],{"class":368},"sa561",[170,370,239],{"class":212},[170,372,373],{"class":294},"True",[170,375,338],{"class":216},[170,377,341],{"class":179},[170,379,344],{"class":216},[170,381,347],{"class":179},[170,383,384],{"class":216},"].value)  ",[170,386,387],{"class":353},"# None\n",[10,389,390,391,394,395,398],{},"Both reads are correct. The first returns the instruction stored in the cell; the second returns the result slot, which no calculation engine has ever filled. Open ",[13,392,393],{},"fresh.xlsx"," in Excel or LibreOffice, save it, and re-run the script: the second line now prints ",[13,396,397],{},"79.96",".",[156,400,402],{"id":401},"detect-a-missing-cache-instead-of-trusting-it","Detect a missing cache instead of trusting it",[10,404,405,406,408,409,411],{},"The dangerous version of this problem is not ",[13,407,19],{}," — it is a ",[13,410,19],{}," that flows into a sum and becomes a plausible-looking zero. Check explicitly at the point of reading:",[161,413,415],{"className":203,"code":414,"language":205,"meta":166,"style":166},"from openpyxl import load_workbook\n\ndef read_values(path, sheet, column, first_row=2):\n    \"\"\"Return the cached results of a formula column, or explain why they're missing.\"\"\"\n    formulas = load_workbook(path)[sheet]\n    values = load_workbook(path, data_only=True)[sheet]\n\n    out, uncached = [], []\n    for row in range(first_row, formulas.max_row + 1):\n        coord = f\"{column}{row}\"\n        source = formulas[coord].value\n        cached = values[coord].value\n        if isinstance(source, str) and source.startswith(\"=\") and cached is None:\n            uncached.append(coord)\n        out.append(cached)\n\n    if uncached:\n        raise ValueError(\n            f\"{len(uncached)} formula cell(s) have no cached result \"\n            f\"(first: {uncached[0]}). Open and save the file in Excel, \"\n            \"or compute these values in Python.\"\n        )\n    return out\n\nprint(read_values(\"orders.xlsx\", \"Orders\", \"D\"))\n",[13,416,417,428,432,452,457,467,486,490,500,525,557,568,579,622,628,634,639,648,660,681,704,710,716,725,730],{"__ignoreMap":166},[170,418,419,421,423,425],{"class":106,"line":172},[170,420,213],{"class":212},[170,422,217],{"class":216},[170,424,220],{"class":212},[170,426,427],{"class":216}," load_workbook\n",[170,429,430],{"class":106,"line":226},[170,431,230],{"emptyLinePlaceholder":229},[170,433,434,437,441,444,446,449],{"class":106,"line":233},[170,435,436],{"class":212},"def",[170,438,440],{"class":439},"s_Opv"," read_values",[170,442,443],{"class":216},"(path, sheet, column, first_row",[170,445,239],{"class":212},[170,447,448],{"class":294},"2",[170,450,451],{"class":216},"):\n",[170,453,454],{"class":106,"line":245},[170,455,456],{"class":179},"    \"\"\"Return the cached results of a formula column, or explain why they're missing.\"\"\"\n",[170,458,459,462,464],{"class":106,"line":256},[170,460,461],{"class":216},"    formulas ",[170,463,239],{"class":212},[170,465,466],{"class":216}," load_workbook(path)[sheet]\n",[170,468,469,472,474,477,479,481,483],{"class":106,"line":284},[170,470,471],{"class":216},"    values ",[170,473,239],{"class":212},[170,475,476],{"class":216}," load_workbook(path, ",[170,478,23],{"class":368},[170,480,239],{"class":212},[170,482,373],{"class":294},[170,484,485],{"class":216},")[sheet]\n",[170,487,488],{"class":106,"line":310},[170,489,230],{"emptyLinePlaceholder":229},[170,491,492,495,497],{"class":106,"line":322},[170,493,494],{"class":216},"    out, uncached ",[170,496,239],{"class":212},[170,498,499],{"class":216}," [], []\n",[170,501,502,505,508,511,514,517,520,523],{"class":106,"line":327},[170,503,504],{"class":212},"    for",[170,506,507],{"class":216}," row ",[170,509,510],{"class":212},"in",[170,512,513],{"class":294}," range",[170,515,516],{"class":216},"(first_row, formulas.max_row ",[170,518,519],{"class":212},"+",[170,521,522],{"class":294}," 1",[170,524,451],{"class":216},[170,526,527,530,532,535,538,542,545,548,551,554],{"class":106,"line":357},[170,528,529],{"class":216},"        coord ",[170,531,239],{"class":212},[170,533,534],{"class":212}," f",[170,536,537],{"class":179},"\"",[170,539,541],{"class":540},"sSjpA","{",[170,543,544],{"class":216},"column",[170,546,547],{"class":540},"}{",[170,549,550],{"class":216},"row",[170,552,553],{"class":540},"}",[170,555,556],{"class":179},"\"\n",[170,558,560,563,565],{"class":106,"line":559},11,[170,561,562],{"class":216},"        source ",[170,564,239],{"class":212},[170,566,567],{"class":216}," formulas[coord].value\n",[170,569,571,574,576],{"class":106,"line":570},12,[170,572,573],{"class":216},"        cached ",[170,575,239],{"class":212},[170,577,578],{"class":216}," values[coord].value\n",[170,580,582,585,588,591,594,597,600,603,606,608,610,613,616,619],{"class":106,"line":581},13,[170,583,584],{"class":212},"        if",[170,586,587],{"class":294}," isinstance",[170,589,590],{"class":216},"(source, ",[170,592,593],{"class":294},"str",[170,595,596],{"class":216},") ",[170,598,599],{"class":212},"and",[170,601,602],{"class":216}," source.startswith(",[170,604,605],{"class":179},"\"=\"",[170,607,596],{"class":216},[170,609,599],{"class":212},[170,611,612],{"class":216}," cached ",[170,614,615],{"class":212},"is",[170,617,618],{"class":294}," None",[170,620,621],{"class":216},":\n",[170,623,625],{"class":106,"line":624},14,[170,626,627],{"class":216},"            uncached.append(coord)\n",[170,629,631],{"class":106,"line":630},15,[170,632,633],{"class":216},"        out.append(cached)\n",[170,635,637],{"class":106,"line":636},16,[170,638,230],{"emptyLinePlaceholder":229},[170,640,642,645],{"class":106,"line":641},17,[170,643,644],{"class":212},"    if",[170,646,647],{"class":216}," uncached:\n",[170,649,651,654,657],{"class":106,"line":650},18,[170,652,653],{"class":212},"        raise",[170,655,656],{"class":294}," ValueError",[170,658,659],{"class":216},"(\n",[170,661,663,666,668,670,673,676,678],{"class":106,"line":662},19,[170,664,665],{"class":212},"            f",[170,667,537],{"class":179},[170,669,541],{"class":540},[170,671,672],{"class":294},"len",[170,674,675],{"class":216},"(uncached)",[170,677,553],{"class":540},[170,679,680],{"class":179}," formula cell(s) have no cached result \"\n",[170,682,684,686,689,691,694,696,699,701],{"class":106,"line":683},20,[170,685,665],{"class":212},[170,687,688],{"class":179},"\"(first: ",[170,690,541],{"class":540},[170,692,693],{"class":216},"uncached[",[170,695,58],{"class":294},[170,697,698],{"class":216},"]",[170,700,553],{"class":540},[170,702,703],{"class":179},"). Open and save the file in Excel, \"\n",[170,705,707],{"class":106,"line":706},21,[170,708,709],{"class":179},"            \"or compute these values in Python.\"\n",[170,711,713],{"class":106,"line":712},22,[170,714,715],{"class":216},"        )\n",[170,717,719,722],{"class":106,"line":718},23,[170,720,721],{"class":212},"    return",[170,723,724],{"class":216}," out\n",[170,726,728],{"class":106,"line":727},24,[170,729,230],{"emptyLinePlaceholder":229},[170,731,733,735,738,741,743,746,748,751],{"class":106,"line":732},25,[170,734,330],{"class":294},[170,736,737],{"class":216},"(read_values(",[170,739,740],{"class":179},"\"orders.xlsx\"",[170,742,265],{"class":216},[170,744,745],{"class":179},"\"Orders\"",[170,747,265],{"class":216},[170,749,750],{"class":179},"\"D\"",[170,752,753],{"class":216},"))\n",[10,755,756,757,760,761,764],{},"Loading the file twice is the key move: one handle knows ",[26,758,759],{},"whether"," a cell is a formula, the other knows ",[26,762,763],{},"what"," it evaluated to. Comparing them separates \"this cell is genuinely empty\" from \"this cell should hold a number and does not\".",[37,766,46,771,46,774,46,777,46,780,46,784,46,789,46,793,46,796,46,801,46,805,46,811,46,815,46,823,46,829,46,835,46,837,46,840,46,845,46,850,46,855,46,858,46,862,46,866,46,869,46,873],{"viewBox":767,"role":40,"ariaLabelledBy":768,"xmlns":44,"style":45},"0 0 760 232",[769,770],"do-two-t","do-two-d",[48,772,773],{"id":769},"Loading the same workbook twice to tell blank cells from uncached formulas",[52,775,776],{"id":770},"One load without data_only reports whether each cell holds a formula. A second load with data_only reports the cached number. Combining them gives three outcomes: a real value, an empty cell, and a formula with no cached result which should raise an error.",[56,778],{"x":58,"y":58,"width":59,"height":779,"fill":61},"232",[56,781],{"x":782,"y":64,"width":783,"height":76,"rx":126,"fill":141,"stroke":142},"30","200",[73,785,788],{"x":786,"y":787,"style":145},"130","47","load default",[73,790,792],{"x":786,"y":791,"style":137},"67","is this a formula?",[56,794],{"x":782,"y":795,"width":783,"height":76,"rx":126,"fill":92,"stroke":93},"140",[73,797,800],{"x":786,"y":798,"style":799},"163","font-size:12.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","load data_only",[73,802,804],{"x":786,"y":803,"style":137},"183","what did it evaluate to?",[106,806],{"x1":807,"y1":808,"x2":809,"y2":810,"stroke":110,"style":111},"234","52","290","98",[106,812],{"x1":807,"y1":813,"x2":809,"y2":814,"stroke":110,"style":111},"168","122",[56,816],{"x":817,"y":818,"width":819,"height":820,"rx":821,"fill":822},"294","86","150","48","10","#5b5cf0",[73,824,828],{"x":825,"y":826,"style":827},"369","116","font-size:13px;font-weight:700;fill:#ffffff;text-anchor:middle","compare",[106,830],{"x1":831,"y1":832,"x2":833,"y2":834,"stroke":110,"style":111},"448","110","486","46",[106,836],{"x1":831,"y1":832,"x2":833,"y2":832,"stroke":110,"style":111},[106,838],{"x1":831,"y1":832,"x2":833,"y2":839,"stroke":110,"style":111},"176",[56,841],{"x":842,"y":843,"width":844,"height":808,"rx":821,"fill":69,"stroke":142},"490","20","244",[73,846,849],{"x":847,"y":848,"style":103},"612","42","formula + number",[73,851,854],{"x":847,"y":852,"style":853},"62","font-size:11.5px;fill:var(--teal,#0f9488);text-anchor:middle","use the number",[56,856],{"x":842,"y":857,"width":844,"height":808,"rx":821,"fill":69,"stroke":142},"84",[73,859,861],{"x":847,"y":860,"style":103},"106","no formula, no value",[73,863,865],{"x":847,"y":864,"style":137},"126","genuinely empty cell",[56,867],{"x":842,"y":868,"width":844,"height":808,"rx":821,"fill":127,"stroke":128},"148",[73,870,872],{"x":847,"y":871,"style":87},"170","formula, no number",[73,874,876],{"x":847,"y":875,"style":137},"190","raise — never treat as zero",[156,878,880],{"id":879},"option-1-let-a-spreadsheet-application-fill-the-cache","Option 1: let a spreadsheet application fill the cache",[10,882,883,884,887],{},"If the workbook is produced by Excel users and consumed by your script, the cache is already there and ",[13,885,886],{},"data_only=True"," is all you need. Read it, and treat a missing cache as a hard failure rather than a zero:",[161,889,891],{"className":203,"code":890,"language":205,"meta":166,"style":166},"from openpyxl import load_workbook\n\nwb = load_workbook(\"month_end.xlsx\", data_only=True, read_only=True)\nws = wb[\"Summary\"]\n\nkpis = {ws.cell(row=r, column=1).value: ws.cell(row=r, column=2).value\n        for r in range(2, 8)}\nwb.close()\n\nfor name, value in kpis.items():\n    if value is None:\n        raise SystemExit(f\"KPI {name!r} has no cached value — was the file saved from Excel?\")\nprint(kpis)\n",[13,892,893,903,907,938,953,957,999,1024,1029,1033,1046,1059,1089],{"__ignoreMap":166},[170,894,895,897,899,901],{"class":106,"line":172},[170,896,213],{"class":212},[170,898,217],{"class":216},[170,900,220],{"class":212},[170,902,427],{"class":216},[170,904,905],{"class":106,"line":226},[170,906,230],{"emptyLinePlaceholder":229},[170,908,909,911,913,916,919,921,923,925,927,929,932,934,936],{"class":106,"line":233},[170,910,236],{"class":216},[170,912,239],{"class":212},[170,914,915],{"class":216}," load_workbook(",[170,917,918],{"class":179},"\"month_end.xlsx\"",[170,920,265],{"class":216},[170,922,23],{"class":368},[170,924,239],{"class":212},[170,926,373],{"class":294},[170,928,265],{"class":216},[170,930,931],{"class":368},"read_only",[170,933,239],{"class":212},[170,935,373],{"class":294},[170,937,319],{"class":216},[170,939,940,942,944,947,950],{"class":106,"line":245},[170,941,248],{"class":216},[170,943,239],{"class":212},[170,945,946],{"class":216}," wb[",[170,948,949],{"class":179},"\"Summary\"",[170,951,952],{"class":216},"]\n",[170,954,955],{"class":106,"line":256},[170,956,230],{"emptyLinePlaceholder":229},[170,958,959,962,964,967,969,971,974,976,978,981,984,986,988,990,992,994,996],{"class":106,"line":284},[170,960,961],{"class":216},"kpis ",[170,963,239],{"class":212},[170,965,966],{"class":216}," {ws.cell(",[170,968,550],{"class":368},[170,970,239],{"class":212},[170,972,973],{"class":216},"r, ",[170,975,544],{"class":368},[170,977,239],{"class":212},[170,979,980],{"class":294},"1",[170,982,983],{"class":216},").value: ws.cell(",[170,985,550],{"class":368},[170,987,239],{"class":212},[170,989,973],{"class":216},[170,991,544],{"class":368},[170,993,239],{"class":212},[170,995,448],{"class":294},[170,997,998],{"class":216},").value\n",[170,1000,1001,1004,1007,1009,1011,1014,1016,1018,1021],{"class":106,"line":310},[170,1002,1003],{"class":212},"        for",[170,1005,1006],{"class":216}," r ",[170,1008,510],{"class":212},[170,1010,513],{"class":294},[170,1012,1013],{"class":216},"(",[170,1015,448],{"class":294},[170,1017,265],{"class":216},[170,1019,1020],{"class":294},"8",[170,1022,1023],{"class":216},")}\n",[170,1025,1026],{"class":106,"line":322},[170,1027,1028],{"class":216},"wb.close()\n",[170,1030,1031],{"class":106,"line":327},[170,1032,230],{"emptyLinePlaceholder":229},[170,1034,1035,1038,1041,1043],{"class":106,"line":357},[170,1036,1037],{"class":212},"for",[170,1039,1040],{"class":216}," name, value ",[170,1042,510],{"class":212},[170,1044,1045],{"class":216}," kpis.items():\n",[170,1047,1048,1050,1053,1055,1057],{"class":106,"line":559},[170,1049,644],{"class":212},[170,1051,1052],{"class":216}," value ",[170,1054,615],{"class":212},[170,1056,618],{"class":294},[170,1058,621],{"class":216},[170,1060,1061,1063,1066,1068,1071,1074,1076,1079,1082,1084,1087],{"class":106,"line":570},[170,1062,653],{"class":212},[170,1064,1065],{"class":294}," SystemExit",[170,1067,1013],{"class":216},[170,1069,1070],{"class":212},"f",[170,1072,1073],{"class":179},"\"KPI ",[170,1075,541],{"class":540},[170,1077,1078],{"class":216},"name",[170,1080,1081],{"class":212},"!r",[170,1083,553],{"class":540},[170,1085,1086],{"class":179}," has no cached value — was the file saved from Excel?\"",[170,1088,319],{"class":216},[170,1090,1091,1093],{"class":106,"line":581},[170,1092,330],{"class":294},[170,1094,1095],{"class":216},"(kpis)\n",[10,1097,1098,1101,1102,1104,1105,1108],{},[13,1099,1100],{},"read_only=True"," pairs well with ",[13,1103,886],{}," for this job: you are harvesting numbers, not editing, so streaming the sheet keeps memory flat on a large workbook. Remember to ",[13,1106,1107],{},"close()"," a read-only workbook — it holds an open file handle until you do.",[156,1110,1112],{"id":1111},"option-2-recompute-in-python-and-stop-depending-on-the-cache","Option 2: recompute in Python and stop depending on the cache",[10,1114,1115],{},"When your own code both writes and reads the workbook, the cache is a detour. Compute the figure with pandas, write the number, and optionally keep the formula next to it for the reader:",[161,1117,1119],{"className":203,"code":1118,"language":205,"meta":166,"style":166},"import pandas as pd\nfrom openpyxl import load_workbook\n\ndf = pd.read_excel(\"orders.xlsx\", sheet_name=\"Orders\", usecols=[\"SKU\", \"Quantity\", \"Unit_Price\"])\ndf[\"Line_Total\"] = df[\"Quantity\"] * df[\"Unit_Price\"]\n\nwb = load_workbook(\"orders.xlsx\")\nws = wb[\"Orders\"]\nfor i, total in enumerate(df[\"Line_Total\"], start=2):\n    ws[f\"D{i}\"] = float(total)          # a literal, readable by anything\nws[f\"D{len(df) + 3}\"] = f\"=SUM(D2:D{len(df) + 1})\"   # one formula, for the reader\nwb.save(\"orders_values.xlsx\")\n\nprint(df[\"Line_Total\"].sum())\n",[13,1120,1121,1134,1144,1148,1194,1223,1227,1239,1251,1280,1312,1364,1373,1377],{"__ignoreMap":166},[170,1122,1123,1125,1128,1131],{"class":106,"line":172},[170,1124,220],{"class":212},[170,1126,1127],{"class":216}," pandas ",[170,1129,1130],{"class":212},"as",[170,1132,1133],{"class":216}," pd\n",[170,1135,1136,1138,1140,1142],{"class":106,"line":226},[170,1137,213],{"class":212},[170,1139,217],{"class":216},[170,1141,220],{"class":212},[170,1143,427],{"class":216},[170,1145,1146],{"class":106,"line":233},[170,1147,230],{"emptyLinePlaceholder":229},[170,1149,1150,1153,1155,1158,1160,1162,1165,1167,1169,1171,1174,1176,1179,1182,1184,1187,1189,1192],{"class":106,"line":245},[170,1151,1152],{"class":216},"df ",[170,1154,239],{"class":212},[170,1156,1157],{"class":216}," pd.read_excel(",[170,1159,740],{"class":179},[170,1161,265],{"class":216},[170,1163,1164],{"class":368},"sheet_name",[170,1166,239],{"class":212},[170,1168,745],{"class":179},[170,1170,265],{"class":216},[170,1172,1173],{"class":368},"usecols",[170,1175,239],{"class":212},[170,1177,1178],{"class":216},"[",[170,1180,1181],{"class":179},"\"SKU\"",[170,1183,265],{"class":216},[170,1185,1186],{"class":179},"\"Quantity\"",[170,1188,265],{"class":216},[170,1190,1191],{"class":179},"\"Unit_Price\"",[170,1193,281],{"class":216},[170,1195,1196,1199,1202,1205,1207,1210,1212,1214,1217,1219,1221],{"class":106,"line":256},[170,1197,1198],{"class":216},"df[",[170,1200,1201],{"class":179},"\"Line_Total\"",[170,1203,1204],{"class":216},"] ",[170,1206,239],{"class":212},[170,1208,1209],{"class":216}," df[",[170,1211,1186],{"class":179},[170,1213,1204],{"class":216},[170,1215,1216],{"class":212},"*",[170,1218,1209],{"class":216},[170,1220,1191],{"class":179},[170,1222,952],{"class":216},[170,1224,1225],{"class":106,"line":284},[170,1226,230],{"emptyLinePlaceholder":229},[170,1228,1229,1231,1233,1235,1237],{"class":106,"line":310},[170,1230,236],{"class":216},[170,1232,239],{"class":212},[170,1234,915],{"class":216},[170,1236,740],{"class":179},[170,1238,319],{"class":216},[170,1240,1241,1243,1245,1247,1249],{"class":106,"line":322},[170,1242,248],{"class":216},[170,1244,239],{"class":212},[170,1246,946],{"class":216},[170,1248,745],{"class":179},[170,1250,952],{"class":216},[170,1252,1253,1255,1258,1260,1263,1266,1268,1271,1274,1276,1278],{"class":106,"line":327},[170,1254,1037],{"class":212},[170,1256,1257],{"class":216}," i, total ",[170,1259,510],{"class":212},[170,1261,1262],{"class":294}," enumerate",[170,1264,1265],{"class":216},"(df[",[170,1267,1201],{"class":179},[170,1269,1270],{"class":216},"], ",[170,1272,1273],{"class":368},"start",[170,1275,239],{"class":212},[170,1277,448],{"class":294},[170,1279,451],{"class":216},[170,1281,1282,1285,1287,1290,1292,1295,1297,1299,1301,1303,1306,1309],{"class":106,"line":357},[170,1283,1284],{"class":216},"    ws[",[170,1286,1070],{"class":212},[170,1288,1289],{"class":179},"\"D",[170,1291,541],{"class":540},[170,1293,1294],{"class":216},"i",[170,1296,553],{"class":540},[170,1298,537],{"class":179},[170,1300,1204],{"class":216},[170,1302,239],{"class":212},[170,1304,1305],{"class":294}," float",[170,1307,1308],{"class":216},"(total)          ",[170,1310,1311],{"class":353},"# a literal, readable by anything\n",[170,1313,1314,1317,1319,1321,1323,1325,1328,1330,1333,1335,1337,1339,1341,1343,1346,1348,1350,1352,1354,1356,1358,1361],{"class":106,"line":559},[170,1315,1316],{"class":216},"ws[",[170,1318,1070],{"class":212},[170,1320,1289],{"class":179},[170,1322,541],{"class":540},[170,1324,672],{"class":294},[170,1326,1327],{"class":216},"(df) ",[170,1329,519],{"class":212},[170,1331,1332],{"class":294}," 3",[170,1334,553],{"class":540},[170,1336,537],{"class":179},[170,1338,1204],{"class":216},[170,1340,239],{"class":212},[170,1342,534],{"class":212},[170,1344,1345],{"class":179},"\"=SUM(D2:D",[170,1347,541],{"class":540},[170,1349,672],{"class":294},[170,1351,1327],{"class":216},[170,1353,519],{"class":212},[170,1355,522],{"class":294},[170,1357,553],{"class":540},[170,1359,1360],{"class":179},")\"",[170,1362,1363],{"class":353},"   # one formula, for the reader\n",[170,1365,1366,1368,1371],{"class":106,"line":570},[170,1367,313],{"class":216},[170,1369,1370],{"class":179},"\"orders_values.xlsx\"",[170,1372,319],{"class":216},[170,1374,1375],{"class":106,"line":581},[170,1376,230],{"emptyLinePlaceholder":229},[170,1378,1379,1381,1383,1385],{"class":106,"line":624},[170,1380,330],{"class":294},[170,1382,1265],{"class":216},[170,1384,1201],{"class":179},[170,1386,1387],{"class":216},"].sum())\n",[10,1389,1390],{},"This is the pattern to reach for whenever a downstream system — a database load, a CSV export, another Python job — needs the numbers. Values survive every hop; formulas only survive into applications that can evaluate them.",[156,1392,1394],{"id":1393},"option-3-evaluate-the-formulas-without-excel","Option 3: evaluate the formulas without Excel",[10,1396,1397],{},"Third-party libraries can parse and evaluate an existing workbook's formula graph. They are useful when you receive a modelling workbook you cannot open in Excel on a server, and they are not a drop-in replacement for a spreadsheet application — coverage of Excel's function set and of volatile or array formulas varies:",[161,1399,1401],{"className":163,"code":1400,"language":165,"meta":166,"style":166},"pip install formulas\n",[13,1402,1403],{"__ignoreMap":166},[170,1404,1405,1407,1409],{"class":106,"line":172},[170,1406,176],{"class":175},[170,1408,180],{"class":179},[170,1410,1411],{"class":179}," formulas\n",[161,1413,1415],{"className":203,"code":1414,"language":205,"meta":166,"style":166},"import formulas\n\nmodel = formulas.ExcelModel().loads(\"month_end.xlsx\").finish()\nsolution = model.calculate()\n\n# Keys look like \"'[MONTH_END.XLSX]SUMMARY'!B2\"\nfor key, value in solution.items():\n    if key.endswith(\"!B2\"):\n        print(key, value)\n",[13,1416,1417,1423,1427,1442,1452,1456,1461,1473,1485],{"__ignoreMap":166},[170,1418,1419,1421],{"class":106,"line":172},[170,1420,220],{"class":212},[170,1422,1411],{"class":216},[170,1424,1425],{"class":106,"line":226},[170,1426,230],{"emptyLinePlaceholder":229},[170,1428,1429,1432,1434,1437,1439],{"class":106,"line":233},[170,1430,1431],{"class":216},"model ",[170,1433,239],{"class":212},[170,1435,1436],{"class":216}," formulas.ExcelModel().loads(",[170,1438,918],{"class":179},[170,1440,1441],{"class":216},").finish()\n",[170,1443,1444,1447,1449],{"class":106,"line":245},[170,1445,1446],{"class":216},"solution ",[170,1448,239],{"class":212},[170,1450,1451],{"class":216}," model.calculate()\n",[170,1453,1454],{"class":106,"line":256},[170,1455,230],{"emptyLinePlaceholder":229},[170,1457,1458],{"class":106,"line":284},[170,1459,1460],{"class":353},"# Keys look like \"'[MONTH_END.XLSX]SUMMARY'!B2\"\n",[170,1462,1463,1465,1468,1470],{"class":106,"line":310},[170,1464,1037],{"class":212},[170,1466,1467],{"class":216}," key, value ",[170,1469,510],{"class":212},[170,1471,1472],{"class":216}," solution.items():\n",[170,1474,1475,1477,1480,1483],{"class":106,"line":322},[170,1476,644],{"class":212},[170,1478,1479],{"class":216}," key.endswith(",[170,1481,1482],{"class":179},"\"!B2\"",[170,1484,451],{"class":216},[170,1486,1487,1490],{"class":106,"line":327},[170,1488,1489],{"class":294},"        print",[170,1491,1492],{"class":216},"(key, value)\n",[10,1494,1495],{},"Treat this as an escape hatch. If a calculation matters enough to automate, owning it in pandas is nearly always more predictable than re-evaluating someone else's spreadsheet.",[37,1497,46,1502,46,1505,46,1508,46,1511,46,1516,46,1520,46,1524,46,1528,46,1533,46,1537,46,1540,46,1544,46,1547,46,1551,46,1554,46,1557,46,1561,46,1564,46,1568,46,1571,46,1574,46,1577,46,1580,46,1582,46,1585],{"viewBox":1498,"role":40,"ariaLabelledBy":1499,"xmlns":44,"style":45},"0 0 760 194",[1500,1501],"do-life-t","do-life-d",[48,1503,1504],{"id":1500},"The life of a cached value",[52,1506,1507],{"id":1501},"A timeline in four stages: Python writes the formula and there is no cache, Excel opens and saves so the cache is fresh, Python rewrites the input cells so the cache is now stale, and a recalculation on next open makes it fresh again.",[56,1509],{"x":58,"y":58,"width":59,"height":1510,"fill":61},"194",[106,1512],{"x1":1513,"y1":1514,"x2":1515,"y2":1514,"stroke":142,"style":71},"40","104","720",[1517,1518],"circle",{"cx":832,"cy":1514,"r":1519,"fill":822},"9",[73,1521,1523],{"x":832,"y":125,"style":1522},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Python writes",[73,1525,1527],{"x":832,"y":857,"style":1526},"font-size:11px;fill:var(--muted,#5b6780);text-anchor:middle","the formula",[73,1529,1532],{"x":832,"y":1530,"style":1531},"138","font-size:11.5px;font-weight:700;fill:var(--danger,#dc2626);text-anchor:middle","cache: none",[73,1534,1536],{"x":832,"y":1535,"style":1526},"158","data_only → None",[1517,1538],{"cx":66,"cy":1514,"r":1519,"fill":1539},"#0f766e",[73,1541,1543],{"x":66,"y":125,"style":1542},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Excel saves",[73,1545,1546],{"x":66,"y":857,"style":1526},"the file",[73,1548,1550],{"x":66,"y":1530,"style":1549},"font-size:11.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","cache: fresh",[73,1552,1553],{"x":66,"y":1535,"style":1526},"data_only → 79.96",[1517,1555],{"cx":842,"cy":1514,"r":1519,"fill":1556},"#8a5808",[73,1558,1560],{"x":842,"y":125,"style":1559},"font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Python rewrites",[73,1562,1563],{"x":842,"y":857,"style":1526},"the input cells",[73,1565,1567],{"x":842,"y":1530,"style":1566},"font-size:11.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","cache: stale",[73,1569,1570],{"x":842,"y":1535,"style":1526},"old number, new inputs",[1517,1572],{"cx":1573,"cy":1514,"r":1519,"fill":1539},"680",[73,1575,1576],{"x":1573,"y":125,"style":1542},"recalculated",[73,1578,1579],{"x":1573,"y":857,"style":1526},"on next open",[73,1581,1550],{"x":1573,"y":1530,"style":1549},[73,1583,1584],{"x":1573,"y":1535,"style":1526},"fullCalcOnLoad",[73,1586,1588],{"x":152,"y":65,"style":1587},"font-size:12.5px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","The cache is only as current as the last calculation — not as the last edit.",[156,1590,1592],{"id":1591},"option-4-force-a-recalculation-on-next-open","Option 4: force a recalculation on next open",[10,1594,1595],{},"You cannot make openpyxl calculate, but you can ask the next application that opens the file to recalculate everything rather than trusting its own cache:",[161,1597,1599],{"className":203,"code":1598,"language":205,"meta":166,"style":166},"from openpyxl import load_workbook\n\nwb = load_workbook(\"month_end.xlsx\")\nwb.calculation.fullCalcOnLoad = True\nwb.save(\"month_end.xlsx\")\n",[13,1600,1601,1611,1615,1627,1637],{"__ignoreMap":166},[170,1602,1603,1605,1607,1609],{"class":106,"line":172},[170,1604,213],{"class":212},[170,1606,217],{"class":216},[170,1608,220],{"class":212},[170,1610,427],{"class":216},[170,1612,1613],{"class":106,"line":226},[170,1614,230],{"emptyLinePlaceholder":229},[170,1616,1617,1619,1621,1623,1625],{"class":106,"line":233},[170,1618,236],{"class":216},[170,1620,239],{"class":212},[170,1622,915],{"class":216},[170,1624,918],{"class":179},[170,1626,319],{"class":216},[170,1628,1629,1632,1634],{"class":106,"line":245},[170,1630,1631],{"class":216},"wb.calculation.fullCalcOnLoad ",[170,1633,239],{"class":212},[170,1635,1636],{"class":294}," True\n",[170,1638,1639,1641,1643],{"class":106,"line":256},[170,1640,313],{"class":216},[170,1642,918],{"class":179},[170,1644,319],{"class":216},[10,1646,1647],{},"This matters after your script has rewritten input cells: without the flag, some applications trust cached results whose inputs have changed underneath them, and a reader sees last month's totals over this month's data.",[156,1649,1651],{"id":1650},"which-option-fits-your-situation","Which option fits your situation",[1653,1654,1655,1671],"table",{},[1656,1657,1658],"thead",{},[1659,1660,1661,1665,1668],"tr",{},[1662,1663,1664],"th",{},"Where the workbook comes from",[1662,1666,1667],{},"What you need",[1662,1669,1670],{},"Best option",[1672,1673,1674,1691,1702,1713,1726],"tbody",{},[1659,1675,1676,1680,1683],{},[1677,1678,1679],"td",{},"Produced by Excel users, read by your script",[1677,1681,1682],{},"The numbers they see",[1677,1684,1685,1687,1688,1690],{},[13,1686,886],{},", treat ",[13,1689,19],{}," as a failure",[1659,1692,1693,1696,1699],{},[1677,1694,1695],{},"Produced and read by your own pipeline",[1677,1697,1698],{},"Reliable values",[1677,1700,1701],{},"Compute in pandas, write literals",[1659,1703,1704,1707,1710],{},[1677,1705,1706],{},"A third-party model you cannot open in Excel",[1677,1708,1709],{},"Derived figures",[1677,1711,1712],{},"A formula-evaluation library, with spot checks",[1659,1714,1715,1718,1721],{},[1677,1716,1717],{},"Your script edits inputs, a person opens it later",[1677,1719,1720],{},"Fresh results for the reader",[1677,1722,1723,1724],{},"Write formulas, set ",[13,1725,1584],{},[1659,1727,1728,1731,1734],{},[1677,1729,1730],{},"Archive that must never change",[1677,1732,1733],{},"Frozen numbers",[1677,1735,1736],{},"Freeze the cached values into literals",[10,1738,1739,1740,1742,1743,1745],{},"The row that catches most teams out is the second one. It is tempting to keep writing formulas because the file looks richer, then to bolt on a ",[13,1741,23],{}," read at the end of the pipeline — which works on a developer machine where Excel has opened the file, and returns ",[13,1744,19],{}," on the server where nothing ever does.",[156,1747,1749],{"id":1748},"common-pitfalls-and-gotchas","Common pitfalls and gotchas",[1653,1751,1752,1765],{},[1656,1753,1754],{},[1659,1755,1756,1759,1762],{},[1662,1757,1758],{},"Symptom",[1662,1760,1761],{},"Cause",[1662,1763,1764],{},"Fix",[1672,1766,1767,1780,1797,1811,1827,1841],{},[1659,1768,1769,1774,1777],{},[1677,1770,1771,1772],{},"Whole column of ",[13,1773,19],{},[1677,1775,1776],{},"File was generated by Python and never opened in Excel",[1677,1778,1779],{},"Recompute in Python, or open and save the file once",[1659,1781,1782,1785,1791],{},[1677,1783,1784],{},"Formulas gone after a save",[1677,1786,1787,1788,1790],{},"Workbook was loaded with ",[13,1789,886],{}," and saved",[1677,1792,1793,1794,1796],{},"Load without ",[13,1795,23],{}," when you intend to keep formulas",[1659,1798,1799,1802,1805],{},[1677,1800,1801],{},"Numbers look like last month's",[1677,1803,1804],{},"Cache is stale relative to rewritten inputs",[1677,1806,1807,1808],{},"Set ",[13,1809,1810],{},"wb.calculation.fullCalcOnLoad = True",[1659,1812,1813,1818,1824],{},[1677,1814,1815],{},[13,1816,1817],{},"ValueError: Workbook is read-only",[1677,1819,1820,1821,1823],{},"Tried to write to a ",[13,1822,1100],{}," handle",[1677,1825,1826],{},"Load a second, writable handle for the edits",[1659,1828,1829,1835,1838],{},[1677,1830,1831,1834],{},[13,1832,1833],{},"#REF!"," string instead of a number",[1677,1836,1837],{},"Excel cached an error result",[1677,1839,1840],{},"Fix the reference; scan for the error strings before publishing",[1659,1842,1843,1846,1851],{},[1677,1844,1845],{},"Sum quietly too low",[1677,1847,1848,1850],{},[13,1849,19],{}," values coerced to zero downstream",[1677,1852,1853],{},"Raise on uncached formulas rather than defaulting",[156,1855,1857],{"id":1856},"performance-and-scale-notes","Performance and scale notes",[10,1859,1860,1862,1863,1865,1866,1868,1869,1872],{},[13,1861,886],{}," does not make loading slower — it reads a different attribute of the same XML — but combining it with ",[13,1864,1100],{}," is what keeps a 200 MB workbook from filling memory. Loading the file twice (once per mode) doubles parse time, so on very large files do it once each and keep the two sheet handles rather than reloading per lookup. If you only need a handful of cells, ",[13,1867,931],{}," plus direct ",[13,1870,1871],{},"ws.cell(row=..., column=...)"," access avoids materialising the entire sheet.",[156,1874,1876],{"id":1875},"conclusion","Conclusion",[10,1878,1879,1881,1882,1884],{},[13,1880,886],{}," is a cache reader, not a calculator. On files that come from Excel users the cache is present and the mode does exactly what you want; on files your own code generated it is empty by definition. Detect the difference explicitly, never let ",[13,1883,19],{}," become a silent zero, and when your pipeline owns the numbers, compute them in pandas and write literals so no cache is involved at all.",[156,1886,1888],{"id":1887},"frequently-asked-questions","Frequently asked questions",[10,1890,1891,1901],{},[1892,1893,1894,1895,1897,1898,1900],"strong",{},"Why is ",[13,1896,886],{}," returning ",[13,1899,19],{},"?","\nThe workbook has no cached value for that cell. Caches are written by Excel or LibreOffice when they save a file; a workbook generated by Python has never been through a calculation engine.",[10,1903,1904,1907,1908,1911,1912,1915],{},[1892,1905,1906],{},"Does openpyxl have a way to calculate formulas itself?","\nNo. If you need fresh numbers without a spreadsheet application, recompute them in Python with pandas, or use a formula-evaluation library such as ",[13,1909,1910],{},"formulas"," or ",[13,1913,1914],{},"pycel"," on the workbook.",[10,1917,1918,1921,1922,1924],{},[1892,1919,1920],{},"Can I open one workbook in both modes at once?","\nYes, and it is the standard pattern — load the file twice, once with ",[13,1923,886],{}," for the numbers and once normally for the formulas and formatting.",[10,1926,1927,1933],{},[1892,1928,1929,1930,1932],{},"Does saving a ",[13,1931,23],{}," workbook lose my formulas?","\nYes. Every formula is replaced by the cached value that was loaded, so only save from that mode when freezing values is exactly what you intend.",[10,1935,1936,1939],{},[1892,1937,1938],{},"Do cached values go stale?","\nThey can. The cache reflects the inputs as of the last save by a calculating application, so editing source cells from Python leaves the old results in place until the file is recalculated.",[156,1941,1943],{"id":1942},"related","Related",[10,1945,1946],{},"Up to the parent guide:",[1948,1949,1950],"ul",{},[1951,1952,1953,1955],"li",{},[31,1954,34],{"href":33}," — writing, generating and freezing formulas.",[10,1957,1958],{},"Related guides:",[1948,1960,1961,1968,1975,1982],{},[1951,1962,1963,1967],{},[31,1964,1966],{"href":1965},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formula-to-excel-cell-with-openpyxl\u002F","Write a Formula to an Excel Cell with openpyxl"," — the write side of the same round trip.",[1951,1969,1970,1974],{},[31,1971,1973],{"href":1972},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fconvert-excel-formulas-to-values-with-python\u002F","Convert Excel Formulas to Values with Python"," — turn cached results into permanent literals.",[1951,1976,1977,1981],{},[31,1978,1980],{"href":1979},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fread-cell-value-from-excel-with-openpyxl\u002F","Read a Cell Value from Excel with openpyxl"," — the basics of reading cells and ranges.",[1951,1983,1984,1988],{},[31,1985,1987],{"href":1986},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fspeed-up-openpyxl-with-read-only-mode\u002F","Speed Up openpyxl with read_only Mode"," — harvesting values from large workbooks.",[1990,1991,1992],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}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 .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":166,"searchDepth":226,"depth":226,"links":1994},[1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007],{"id":158,"depth":226,"text":159},{"id":196,"depth":226,"text":197},{"id":401,"depth":226,"text":402},{"id":879,"depth":226,"text":880},{"id":1111,"depth":226,"text":1112},{"id":1393,"depth":226,"text":1394},{"id":1591,"depth":226,"text":1592},{"id":1650,"depth":226,"text":1651},{"id":1748,"depth":226,"text":1749},{"id":1856,"depth":226,"text":1857},{"id":1875,"depth":226,"text":1876},{"id":1887,"depth":226,"text":1888},{"id":1942,"depth":226,"text":1943},"2026-08-01","Why openpyxl returns None for formula cells with data_only=True, how cached values really work, and four reliable ways to get the numbers a workbook is supposed to contain.","md",[2012,2015,2017,2019,2022],{"q":2013,"a":2014},"Why is data_only=True returning None?","The workbook has no cached value for that cell. Caches are written by Excel or LibreOffice when they save a file; a workbook generated by Python has never been through a calculation engine.",{"q":1906,"a":2016},"No. If you need fresh numbers without a spreadsheet application, recompute them in Python with pandas, or use a formula-evaluation library such as formulas or pycel on the workbook.",{"q":1920,"a":2018},"Yes, and it is the standard pattern — load the file twice, once with data_only=True for the numbers and once normally for the formulas and formatting.",{"q":2020,"a":2021},"Does saving a data_only workbook lose my formulas?","Yes. Every formula is replaced by the cached value that was loaded, so only save from that mode when freezing values is exactly what you intend.",{"q":1938,"a":2023},"They can. The cache reflects the inputs as of the last save by a calculating application, so editing source cells from Python leaves the old results in place until the file is recalculated.",{"breadcrumb":2025},[2026,2029,2032,2033],{"name":2027,"item":2028},"Home","\u002F",{"name":2030,"item":2031},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":34,"item":33},{"name":5,"item":2034},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002F","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only",{"title":5,"description":2037},"data_only=True reads Excel's cached values, not fresh calculations. Learn when they exist, how to detect missing caches, and the alternatives when there are none.","read-formula-results-with-openpyxl-data-only","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002Findex","how-to","3z5UveyjZLmlsiPW-k_xMLdMhm14Fc4b8H_MVbExJe0",[2043,2047],{"title":2044,"path":2045,"stem":2046,"children":-1},"Create a Named Range in Excel with openpyxl","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcreate-named-range-in-excel-with-openpyxl","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcreate-named-range-in-excel-with-openpyxl\u002Findex",{"title":1966,"path":2048,"stem":2049,"children":-1},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formula-to-excel-cell-with-openpyxl","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formula-to-excel-cell-with-openpyxl\u002Findex",1785584462714]