[{"data":1,"prerenderedAt":2197},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fwork-with-named-ranges-and-tables-in-xlwings":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fwork-with-named-ranges-and-tables-in-xlwings":2163,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fwork-with-named-ranges-and-tables-in-xlwings":2172,"children:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fwork-with-named-ranges-and-tables-in-xlwings":2177,"related:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fwork-with-named-ranges-and-tables-in-xlwings":2178},{"id":4,"title":5,"body":6,"dateModified":2130,"datePublished":2130,"description":2131,"extension":2132,"faq":2133,"keyword":2142,"kind":2143,"meta":2144,"navigation":163,"path":2154,"seo":2155,"slug":2157,"stem":2158,"topics":2159,"type":2161,"__hash__":2162},"docs\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fwork-with-named-ranges-and-tables-in-xlwings\u002Findex.md","Work with Named Ranges and Tables in xlwings",{"type":7,"value":8,"toc":2117},"minimark",[9,55,60,91,105,109,527,551,555,562,745,790,901,905,911,1033,1050,1054,1063,1268,1301,1459,1463,1495,1499,1505,1842,1856,1955,1959,2010,2014,2045,2049,2058,2064,2074,2080,2084,2113],[10,11,12,13,17,18,22,23,26,27,30,31,34,35,38,39,41,42,44,45,48,49,54],"p",{},"Scripts that drive a live workbook through cell addresses are fragile. ",[14,15,16],"code",{},"sheet[\"B7\"]"," is the tax rate today; next month someone inserts a row above it and the script reads a label instead. Excel's own answer is to give things names: a ",[19,20,21],"em",{},"named range"," for a single input or result — ",[14,24,25],{},"TaxRate",", ",[14,28,29],{},"ForecastTotal"," — and a ",[19,32,33],{},"table"," for a block of records — ",[14,36,37],{},"Sales"," — which grows as rows are added and keeps its name wherever it moves. xlwings exposes both, so a script can read ",[14,40,25],{}," and the ",[14,43,37],{}," table without knowing where they are. This page reads and writes named ranges, manages names at workbook and sheet scope, reads a table into pandas, writes a DataFrame back with ",[14,46,47],{},"update()"," so the table resizes to fit, switches on a totals row, and creates a new table from Python. It belongs to ",[50,51,53],"a",{"href":52},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002F","Automating Excel with xlwings Basics",".",[56,57,59],"h2",{"id":58},"prerequisites","Prerequisites",[61,62,67],"pre",{"className":63,"code":64,"language":65,"meta":66,"style":66},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install xlwings pandas openpyxl\n","bash","",[14,68,69],{"__ignoreMap":66},[70,71,74,78,82,85,88],"span",{"class":72,"line":73},"line",1,[70,75,77],{"class":76},"sMTad","pip",[70,79,81],{"class":80},"srMev"," install",[70,83,84],{"class":80}," xlwings",[70,86,87],{"class":80}," pandas",[70,89,90],{"class":80}," openpyxl\n",[10,92,93,94,97,98,101,102,104],{},"xlwings needs desktop Excel on Windows or macOS; the xlwings code below is shown as it runs against Excel. The example workbook — an ",[19,95,96],{},"Inputs"," sheet with a named tax rate and a ",[19,99,100],{},"Data"," sheet with a ",[19,103,37],{}," table — is created with openpyxl in the first step, which runs anywhere, so you can reproduce the setup exactly.",[56,106,108],{"id":107},"step-1-a-workbook-with-names-and-a-table","Step 1 — A workbook with names and a table",[61,110,114],{"className":111,"code":112,"language":113,"meta":66,"style":66},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\nfrom openpyxl.workbook.defined_name import DefinedName\nfrom openpyxl.worksheet.table import Table, TableStyleInfo\n\nwb = Workbook()\ninputs = wb.active\ninputs.title = \"Inputs\"\ninputs[\"A2\"], inputs[\"B2\"] = \"Tax rate\", 0.2\ninputs[\"A3\"], inputs[\"B3\"] = \"Net total\", None\nwb.defined_names[\"TaxRate\"] = DefinedName(\"TaxRate\", attr_text=\"Inputs!$B$2\")\nwb.defined_names[\"NetTotal\"] = DefinedName(\"NetTotal\", attr_text=\"Inputs!$B$3\")\n\ndata = wb.create_sheet(\"Data\")\ndata.append([\"Region\", \"Product\", \"Net\"])\nfor row in [(\"North\", \"Bolts\", 1250.0), (\"South\", \"Nuts\", 380.5), (\"East\", \"Washers\", 92.0)]:\n    data.append(row)\nsales = Table(displayName=\"Sales\", ref=\"A1:C4\")\nsales.tableStyleInfo = TableStyleInfo(name=\"TableStyleMedium2\", showRowStripes=True)\ndata.add_table(sales)\nwb.save(\"names_and_tables.xlsx\")\nprint(list(wb.defined_names), \"|\", list(data.tables))\n","python",[14,115,116,132,145,158,165,177,188,199,228,253,285,312,317,333,355,417,423,454,485,491,502],{"__ignoreMap":66},[70,117,118,122,126,129],{"class":72,"line":73},[70,119,121],{"class":120},"s-kum","from",[70,123,125],{"class":124},"skGVy"," openpyxl ",[70,127,128],{"class":120},"import",[70,130,131],{"class":124}," Workbook\n",[70,133,135,137,140,142],{"class":72,"line":134},2,[70,136,121],{"class":120},[70,138,139],{"class":124}," openpyxl.workbook.defined_name ",[70,141,128],{"class":120},[70,143,144],{"class":124}," DefinedName\n",[70,146,148,150,153,155],{"class":72,"line":147},3,[70,149,121],{"class":120},[70,151,152],{"class":124}," openpyxl.worksheet.table ",[70,154,128],{"class":120},[70,156,157],{"class":124}," Table, TableStyleInfo\n",[70,159,161],{"class":72,"line":160},4,[70,162,164],{"emptyLinePlaceholder":163},true,"\n",[70,166,168,171,174],{"class":72,"line":167},5,[70,169,170],{"class":124},"wb ",[70,172,173],{"class":120},"=",[70,175,176],{"class":124}," Workbook()\n",[70,178,180,183,185],{"class":72,"line":179},6,[70,181,182],{"class":124},"inputs ",[70,184,173],{"class":120},[70,186,187],{"class":124}," wb.active\n",[70,189,191,194,196],{"class":72,"line":190},7,[70,192,193],{"class":124},"inputs.title ",[70,195,173],{"class":120},[70,197,198],{"class":80}," \"Inputs\"\n",[70,200,202,205,208,211,214,217,219,222,224],{"class":72,"line":201},8,[70,203,204],{"class":124},"inputs[",[70,206,207],{"class":80},"\"A2\"",[70,209,210],{"class":124},"], inputs[",[70,212,213],{"class":80},"\"B2\"",[70,215,216],{"class":124},"] ",[70,218,173],{"class":120},[70,220,221],{"class":80}," \"Tax rate\"",[70,223,26],{"class":124},[70,225,227],{"class":226},"sP0c6","0.2\n",[70,229,231,233,236,238,241,243,245,248,250],{"class":72,"line":230},9,[70,232,204],{"class":124},[70,234,235],{"class":80},"\"A3\"",[70,237,210],{"class":124},[70,239,240],{"class":80},"\"B3\"",[70,242,216],{"class":124},[70,244,173],{"class":120},[70,246,247],{"class":80}," \"Net total\"",[70,249,26],{"class":124},[70,251,252],{"class":226},"None\n",[70,254,256,259,262,264,266,269,271,273,277,279,282],{"class":72,"line":255},10,[70,257,258],{"class":124},"wb.defined_names[",[70,260,261],{"class":80},"\"TaxRate\"",[70,263,216],{"class":124},[70,265,173],{"class":120},[70,267,268],{"class":124}," DefinedName(",[70,270,261],{"class":80},[70,272,26],{"class":124},[70,274,276],{"class":275},"sa561","attr_text",[70,278,173],{"class":120},[70,280,281],{"class":80},"\"Inputs!$B$2\"",[70,283,284],{"class":124},")\n",[70,286,288,290,293,295,297,299,301,303,305,307,310],{"class":72,"line":287},11,[70,289,258],{"class":124},[70,291,292],{"class":80},"\"NetTotal\"",[70,294,216],{"class":124},[70,296,173],{"class":120},[70,298,268],{"class":124},[70,300,292],{"class":80},[70,302,26],{"class":124},[70,304,276],{"class":275},[70,306,173],{"class":120},[70,308,309],{"class":80},"\"Inputs!$B$3\"",[70,311,284],{"class":124},[70,313,315],{"class":72,"line":314},12,[70,316,164],{"emptyLinePlaceholder":163},[70,318,320,323,325,328,331],{"class":72,"line":319},13,[70,321,322],{"class":124},"data ",[70,324,173],{"class":120},[70,326,327],{"class":124}," wb.create_sheet(",[70,329,330],{"class":80},"\"Data\"",[70,332,284],{"class":124},[70,334,336,339,342,344,347,349,352],{"class":72,"line":335},14,[70,337,338],{"class":124},"data.append([",[70,340,341],{"class":80},"\"Region\"",[70,343,26],{"class":124},[70,345,346],{"class":80},"\"Product\"",[70,348,26],{"class":124},[70,350,351],{"class":80},"\"Net\"",[70,353,354],{"class":124},"])\n",[70,356,358,361,364,367,370,373,375,378,380,383,386,389,391,394,396,399,401,404,406,409,411,414],{"class":72,"line":357},15,[70,359,360],{"class":120},"for",[70,362,363],{"class":124}," row ",[70,365,366],{"class":120},"in",[70,368,369],{"class":124}," [(",[70,371,372],{"class":80},"\"North\"",[70,374,26],{"class":124},[70,376,377],{"class":80},"\"Bolts\"",[70,379,26],{"class":124},[70,381,382],{"class":226},"1250.0",[70,384,385],{"class":124},"), (",[70,387,388],{"class":80},"\"South\"",[70,390,26],{"class":124},[70,392,393],{"class":80},"\"Nuts\"",[70,395,26],{"class":124},[70,397,398],{"class":226},"380.5",[70,400,385],{"class":124},[70,402,403],{"class":80},"\"East\"",[70,405,26],{"class":124},[70,407,408],{"class":80},"\"Washers\"",[70,410,26],{"class":124},[70,412,413],{"class":226},"92.0",[70,415,416],{"class":124},")]:\n",[70,418,420],{"class":72,"line":419},16,[70,421,422],{"class":124},"    data.append(row)\n",[70,424,426,429,431,434,437,439,442,444,447,449,452],{"class":72,"line":425},17,[70,427,428],{"class":124},"sales ",[70,430,173],{"class":120},[70,432,433],{"class":124}," Table(",[70,435,436],{"class":275},"displayName",[70,438,173],{"class":120},[70,440,441],{"class":80},"\"Sales\"",[70,443,26],{"class":124},[70,445,446],{"class":275},"ref",[70,448,173],{"class":120},[70,450,451],{"class":80},"\"A1:C4\"",[70,453,284],{"class":124},[70,455,457,460,462,465,468,470,473,475,478,480,483],{"class":72,"line":456},18,[70,458,459],{"class":124},"sales.tableStyleInfo ",[70,461,173],{"class":120},[70,463,464],{"class":124}," TableStyleInfo(",[70,466,467],{"class":275},"name",[70,469,173],{"class":120},[70,471,472],{"class":80},"\"TableStyleMedium2\"",[70,474,26],{"class":124},[70,476,477],{"class":275},"showRowStripes",[70,479,173],{"class":120},[70,481,482],{"class":226},"True",[70,484,284],{"class":124},[70,486,488],{"class":72,"line":487},19,[70,489,490],{"class":124},"data.add_table(sales)\n",[70,492,494,497,500],{"class":72,"line":493},20,[70,495,496],{"class":124},"wb.save(",[70,498,499],{"class":80},"\"names_and_tables.xlsx\"",[70,501,284],{"class":124},[70,503,505,508,511,514,517,520,522,524],{"class":72,"line":504},21,[70,506,507],{"class":226},"print",[70,509,510],{"class":124},"(",[70,512,513],{"class":226},"list",[70,515,516],{"class":124},"(wb.defined_names), ",[70,518,519],{"class":80},"\"|\"",[70,521,26],{"class":124},[70,523,513],{"class":226},[70,525,526],{"class":124},"(data.tables))\n",[10,528,529,530,532,533,535,536,538,539,542,543,546,547,54],{},"Two workbook-level names point at single cells on ",[19,531,96],{},", and the ",[19,534,100],{}," sheet holds a three-row table named ",[19,537,37],{},". These are exactly the objects people create in Excel with ",[19,540,541],{},"Formulas › Define Name"," and ",[19,544,545],{},"Insert › Table","; creating them in Python is covered in ",[50,548,550],{"href":549},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcreate-named-range-in-excel-with-openpyxl\u002F","Create a Named Range in Excel with openpyxl",[56,552,554],{"id":553},"step-2-read-and-write-named-ranges","Step 2 — Read and write named ranges",[10,556,557,558,561],{},"With the workbook open in Excel, a name can be used anywhere xlwings accepts an address, or looked up through ",[14,559,560],{},"book.names",":",[61,563,565],{"className":111,"code":564,"language":113,"meta":66,"style":66},"import xlwings as xw\n\nbook = xw.Book(\"names_and_tables.xlsx\")\nrate = book.sheets[\"Inputs\"][\"TaxRate\"].value                 # 0.2 — the name works as an address\nname = book.names[\"TaxRate\"]\nname.refers_to                                               # '=Inputs!$B$2'\nname.refers_to_range.value                                   # 0.2 — the same cell through the Name object\n[n.name for n in book.names]                                 # ['NetTotal', 'TaxRate']\n\nbook.names[\"NetTotal\"].refers_to_range.value = 1722.5         # write a result to the named cell\nbook.names.add(\"Region\", \"=Inputs!$B$5\")                      # a new workbook-level name\nbook.sheets[\"Data\"].names.add(\"FirstRegion\", \"=Data!$A$2\")    # a name scoped to one sheet\nbook.names[\"Region\"].delete()\n",[14,566,567,580,584,598,623,638,646,654,672,676,694,712,736],{"__ignoreMap":66},[70,568,569,571,574,577],{"class":72,"line":73},[70,570,128],{"class":120},[70,572,573],{"class":124}," xlwings ",[70,575,576],{"class":120},"as",[70,578,579],{"class":124}," xw\n",[70,581,582],{"class":72,"line":134},[70,583,164],{"emptyLinePlaceholder":163},[70,585,586,589,591,594,596],{"class":72,"line":147},[70,587,588],{"class":124},"book ",[70,590,173],{"class":120},[70,592,593],{"class":124}," xw.Book(",[70,595,499],{"class":80},[70,597,284],{"class":124},[70,599,600,603,605,608,611,614,616,619],{"class":72,"line":160},[70,601,602],{"class":124},"rate ",[70,604,173],{"class":120},[70,606,607],{"class":124}," book.sheets[",[70,609,610],{"class":80},"\"Inputs\"",[70,612,613],{"class":124},"][",[70,615,261],{"class":80},[70,617,618],{"class":124},"].value                 ",[70,620,622],{"class":621},"s-wDw","# 0.2 — the name works as an address\n",[70,624,625,628,630,633,635],{"class":72,"line":167},[70,626,627],{"class":124},"name ",[70,629,173],{"class":120},[70,631,632],{"class":124}," book.names[",[70,634,261],{"class":80},[70,636,637],{"class":124},"]\n",[70,639,640,643],{"class":72,"line":179},[70,641,642],{"class":124},"name.refers_to                                               ",[70,644,645],{"class":621},"# '=Inputs!$B$2'\n",[70,647,648,651],{"class":72,"line":190},[70,649,650],{"class":124},"name.refers_to_range.value                                   ",[70,652,653],{"class":621},"# 0.2 — the same cell through the Name object\n",[70,655,656,659,661,664,666,669],{"class":72,"line":201},[70,657,658],{"class":124},"[n.name ",[70,660,360],{"class":120},[70,662,663],{"class":124}," n ",[70,665,366],{"class":120},[70,667,668],{"class":124}," book.names]                                 ",[70,670,671],{"class":621},"# ['NetTotal', 'TaxRate']\n",[70,673,674],{"class":72,"line":230},[70,675,164],{"emptyLinePlaceholder":163},[70,677,678,681,683,686,688,691],{"class":72,"line":255},[70,679,680],{"class":124},"book.names[",[70,682,292],{"class":80},[70,684,685],{"class":124},"].refers_to_range.value ",[70,687,173],{"class":120},[70,689,690],{"class":226}," 1722.5",[70,692,693],{"class":621},"         # write a result to the named cell\n",[70,695,696,699,701,703,706,709],{"class":72,"line":287},[70,697,698],{"class":124},"book.names.add(",[70,700,341],{"class":80},[70,702,26],{"class":124},[70,704,705],{"class":80},"\"=Inputs!$B$5\"",[70,707,708],{"class":124},")                      ",[70,710,711],{"class":621},"# a new workbook-level name\n",[70,713,714,717,719,722,725,727,730,733],{"class":72,"line":314},[70,715,716],{"class":124},"book.sheets[",[70,718,330],{"class":80},[70,720,721],{"class":124},"].names.add(",[70,723,724],{"class":80},"\"FirstRegion\"",[70,726,26],{"class":124},[70,728,729],{"class":80},"\"=Data!$A$2\"",[70,731,732],{"class":124},")    ",[70,734,735],{"class":621},"# a name scoped to one sheet\n",[70,737,738,740,742],{"class":72,"line":319},[70,739,680],{"class":124},[70,741,341],{"class":80},[70,743,744],{"class":124},"].delete()\n",[10,746,747,750,751,754,755,758,759,761,762,765,766,769,770,773,774,777,778,781,782,785,786,789],{},[14,748,749],{},"sheet[\"TaxRate\"]"," resolves the name to its range, so reading and writing look the same as with an address. The ",[14,752,753],{},"Name"," object adds what the address cannot: ",[14,756,757],{},"refers_to"," gives the definition as Excel stores it, with a leading ",[14,760,173],{},", and ",[14,763,764],{},"refers_to_range"," the ",[14,767,768],{},"Range"," it points at. ",[14,771,772],{},"book.names.add()"," takes the definition in the same ",[14,775,776],{},"=Sheet!$A$1"," form. Names created through ",[14,779,780],{},"sheet.names"," are ",[19,783,784],{},"sheet-scoped",": they exist only on that sheet, so two sheets can each have a ",[14,787,788],{},"FirstRegion"," without clashing — useful in workbooks with one sheet per region or month. Writing results to named output cells, rather than to addresses, means a template designer can move the cells without breaking the script.",[791,792,800,801,800,805,800,809,800,817,800,827,800,838,800,845,800,851,800,856,800,860,800,864,800,868,800,873,800,880,800,885,800,889,800,892,800,895,800,898],"svg",{"viewBox":793,"role":794,"ariaLabelledBy":795,"xmlns":798,"style":799},"4 0 752 233","img",[796,797],"xn-scope-t","xn-scope-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[802,803,804],"title",{"id":796},"Workbook-level and sheet-level names",[806,807,808],"desc",{"id":797},"A workbook-level name such as TaxRate is unique in the workbook and can be used from any sheet. A sheet-level name such as FirstRegion belongs to one sheet, so several sheets can each define the same name.",[810,811],"rect",{"x":812,"y":813,"width":814,"height":815,"fill":816},"4","0","752","233","#ffffff",[810,818],{"x":819,"y":820,"width":821,"height":822,"rx":823,"fill":824,"stroke":825,"style":826},"20.0","16.0","351.0","201.0","14","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[828,829,831],"g",{"transform":830},"translate(182.5,29.0) scale(1.083)",[832,833],"path",{"d":834,"fill":835,"stroke":836,"style":837},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","none","var(--brand-strong,#4338ca)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[839,840,844],"text",{"x":841,"y":842,"style":843},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Workbook name (book.names)",[72,846],{"x1":847,"y1":848,"x2":849,"y2":848,"stroke":825,"style":850},"36.0","91.0","355.0","stroke-width:1px",[839,852,855],{"x":841,"y":853,"style":854},"111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","TaxRate → Inputs!$B$2",[839,857,859],{"x":841,"y":858,"style":854},"137.0","unique in the workbook",[839,861,863],{"x":841,"y":862,"style":854},"163.0","usable from any sheet",[839,865,867],{"x":841,"y":866,"style":854},"189.0","inputs and results",[810,869],{"x":870,"y":820,"width":821,"height":822,"rx":823,"fill":871,"stroke":872,"style":826},"389.0","#d9f4f1","var(--teal,#0f9488)",[828,874,876],{"transform":875},"translate(551.5,29.0) scale(1.083)",[832,877],{"d":878,"fill":835,"stroke":879,"style":837},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","var(--teal-ink,#0b6157)",[839,881,884],{"x":882,"y":842,"style":883},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Sheet name (sheet.names)",[72,886],{"x1":887,"y1":848,"x2":888,"y2":848,"stroke":872,"style":850},"405.0","724.0",[839,890,891],{"x":882,"y":853,"style":854},"FirstRegion → Data!$A$2",[839,893,894],{"x":882,"y":858,"style":854},"one per sheet",[839,896,897],{"x":882,"y":862,"style":854},"same name on many sheets",[839,899,900],{"x":882,"y":866,"style":854},"per-region templates",[56,902,904],{"id":903},"step-3-read-a-table-into-pandas","Step 3 — Read a table into pandas",[10,906,907,910],{},[14,908,909],{},"sheet.tables"," holds the tables on a sheet, and each table offers its parts as ranges:",[61,912,914],{"className":111,"code":913,"language":113,"meta":66,"style":66},"import pandas as pd\n\ntable = book.sheets[\"Data\"].tables[\"Sales\"]\ntable.range.address                       # '$A$1:$C$4' — header and data\ntable.data_body_range.address             # '$A$2:$C$4' — data only\ntable.header_row_range.value              # ['Region', 'Product', 'Net']\ndf = table.range.options(pd.DataFrame, index=False).value\ndf[\"Gross\"] = df[\"Net\"] * (1 + book.names[\"TaxRate\"].refers_to_range.value)\n",[14,915,916,928,932,950,958,966,974,995],{"__ignoreMap":66},[70,917,918,920,923,925],{"class":72,"line":73},[70,919,128],{"class":120},[70,921,922],{"class":124}," pandas ",[70,924,576],{"class":120},[70,926,927],{"class":124}," pd\n",[70,929,930],{"class":72,"line":134},[70,931,164],{"emptyLinePlaceholder":163},[70,933,934,937,939,941,943,946,948],{"class":72,"line":147},[70,935,936],{"class":124},"table ",[70,938,173],{"class":120},[70,940,607],{"class":124},[70,942,330],{"class":80},[70,944,945],{"class":124},"].tables[",[70,947,441],{"class":80},[70,949,637],{"class":124},[70,951,952,955],{"class":72,"line":160},[70,953,954],{"class":124},"table.range.address                       ",[70,956,957],{"class":621},"# '$A$1:$C$4' — header and data\n",[70,959,960,963],{"class":72,"line":167},[70,961,962],{"class":124},"table.data_body_range.address             ",[70,964,965],{"class":621},"# '$A$2:$C$4' — data only\n",[70,967,968,971],{"class":72,"line":179},[70,969,970],{"class":124},"table.header_row_range.value              ",[70,972,973],{"class":621},"# ['Region', 'Product', 'Net']\n",[70,975,976,979,981,984,987,989,992],{"class":72,"line":190},[70,977,978],{"class":124},"df ",[70,980,173],{"class":120},[70,982,983],{"class":124}," table.range.options(pd.DataFrame, ",[70,985,986],{"class":275},"index",[70,988,173],{"class":120},[70,990,991],{"class":226},"False",[70,993,994],{"class":124},").value\n",[70,996,997,1000,1003,1005,1007,1010,1012,1014,1017,1020,1023,1026,1028,1030],{"class":72,"line":201},[70,998,999],{"class":124},"df[",[70,1001,1002],{"class":80},"\"Gross\"",[70,1004,216],{"class":124},[70,1006,173],{"class":120},[70,1008,1009],{"class":124}," df[",[70,1011,351],{"class":80},[70,1013,216],{"class":124},[70,1015,1016],{"class":120},"*",[70,1018,1019],{"class":124}," (",[70,1021,1022],{"class":226},"1",[70,1024,1025],{"class":120}," +",[70,1027,632],{"class":124},[70,1029,261],{"class":80},[70,1031,1032],{"class":124},"].refers_to_range.value)\n",[10,1034,1035,1038,1039,1042,1043,1045,1046,54],{},[14,1036,1037],{},"table.range"," covers the header and the data rows, so reading it with the DataFrame converter and ",[14,1040,1041],{},"index=False"," gives a DataFrame with the table's column names and every row — however many there are today. Nothing in the script mentions A1 or C4, so rows added in Excel, or the table moving to another position, need no code change. Without ",[14,1044,1041],{},", the first column would become the DataFrame index, as explained in ",[50,1047,1049],{"href":1048},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fcontrol-how-xlwings-converts-dataframes-and-ranges\u002F","Control How xlwings Converts DataFrames and Ranges",[56,1051,1053],{"id":1052},"step-4-write-back-with-update-add-totals-create-tables","Step 4 — Write back with update(), add totals, create tables",[10,1055,1056,1059,1060,561],{},[14,1057,1058],{},"Table.update()"," writes a DataFrame into the table ",[19,1061,1062],{},"and resizes the table to fit it",[61,1064,1066],{"className":111,"code":1065,"language":113,"meta":66,"style":66},"df = df.sort_values(\"Net\", ascending=False)\ntable.update(df, index=False)              # table now has four columns and the same rows\ntable.show_totals = True                   # Excel adds a totals row; set each column's function in Excel or via table.api\nbook.names[\"NetTotal\"].refers_to_range.value = float(df[\"Net\"].sum())\n\nsummary = df.groupby(\"Region\", as_index=False)[\"Gross\"].sum()\nout = book.sheets.add(\"Summary\")\nout[\"A1\"].options(index=False).value = summary\nnew = out.tables.add(source=out[\"A1\"].expand(), name=\"RegionSummary\", table_style_name=\"TableStyleLight9\")\nnew.name                                   # 'RegionSummary'\nbook.save()\n",[14,1067,1068,1090,1107,1120,1141,1145,1174,1189,1214,1255,1263],{"__ignoreMap":66},[70,1069,1070,1072,1074,1077,1079,1081,1084,1086,1088],{"class":72,"line":73},[70,1071,978],{"class":124},[70,1073,173],{"class":120},[70,1075,1076],{"class":124}," df.sort_values(",[70,1078,351],{"class":80},[70,1080,26],{"class":124},[70,1082,1083],{"class":275},"ascending",[70,1085,173],{"class":120},[70,1087,991],{"class":226},[70,1089,284],{"class":124},[70,1091,1092,1095,1097,1099,1101,1104],{"class":72,"line":134},[70,1093,1094],{"class":124},"table.update(df, ",[70,1096,986],{"class":275},[70,1098,173],{"class":120},[70,1100,991],{"class":226},[70,1102,1103],{"class":124},")              ",[70,1105,1106],{"class":621},"# table now has four columns and the same rows\n",[70,1108,1109,1112,1114,1117],{"class":72,"line":147},[70,1110,1111],{"class":124},"table.show_totals ",[70,1113,173],{"class":120},[70,1115,1116],{"class":226}," True",[70,1118,1119],{"class":621},"                   # Excel adds a totals row; set each column's function in Excel or via table.api\n",[70,1121,1122,1124,1126,1128,1130,1133,1136,1138],{"class":72,"line":160},[70,1123,680],{"class":124},[70,1125,292],{"class":80},[70,1127,685],{"class":124},[70,1129,173],{"class":120},[70,1131,1132],{"class":226}," float",[70,1134,1135],{"class":124},"(df[",[70,1137,351],{"class":80},[70,1139,1140],{"class":124},"].sum())\n",[70,1142,1143],{"class":72,"line":167},[70,1144,164],{"emptyLinePlaceholder":163},[70,1146,1147,1150,1152,1155,1157,1159,1162,1164,1166,1169,1171],{"class":72,"line":179},[70,1148,1149],{"class":124},"summary ",[70,1151,173],{"class":120},[70,1153,1154],{"class":124}," df.groupby(",[70,1156,341],{"class":80},[70,1158,26],{"class":124},[70,1160,1161],{"class":275},"as_index",[70,1163,173],{"class":120},[70,1165,991],{"class":226},[70,1167,1168],{"class":124},")[",[70,1170,1002],{"class":80},[70,1172,1173],{"class":124},"].sum()\n",[70,1175,1176,1179,1181,1184,1187],{"class":72,"line":190},[70,1177,1178],{"class":124},"out ",[70,1180,173],{"class":120},[70,1182,1183],{"class":124}," book.sheets.add(",[70,1185,1186],{"class":80},"\"Summary\"",[70,1188,284],{"class":124},[70,1190,1191,1194,1197,1200,1202,1204,1206,1209,1211],{"class":72,"line":201},[70,1192,1193],{"class":124},"out[",[70,1195,1196],{"class":80},"\"A1\"",[70,1198,1199],{"class":124},"].options(",[70,1201,986],{"class":275},[70,1203,173],{"class":120},[70,1205,991],{"class":226},[70,1207,1208],{"class":124},").value ",[70,1210,173],{"class":120},[70,1212,1213],{"class":124}," summary\n",[70,1215,1216,1219,1221,1224,1227,1229,1231,1233,1236,1238,1240,1243,1245,1248,1250,1253],{"class":72,"line":230},[70,1217,1218],{"class":124},"new ",[70,1220,173],{"class":120},[70,1222,1223],{"class":124}," out.tables.add(",[70,1225,1226],{"class":275},"source",[70,1228,173],{"class":120},[70,1230,1193],{"class":124},[70,1232,1196],{"class":80},[70,1234,1235],{"class":124},"].expand(), ",[70,1237,467],{"class":275},[70,1239,173],{"class":120},[70,1241,1242],{"class":80},"\"RegionSummary\"",[70,1244,26],{"class":124},[70,1246,1247],{"class":275},"table_style_name",[70,1249,173],{"class":120},[70,1251,1252],{"class":80},"\"TableStyleLight9\"",[70,1254,284],{"class":124},[70,1256,1257,1260],{"class":72,"line":255},[70,1258,1259],{"class":124},"new.name                                   ",[70,1261,1262],{"class":621},"# 'RegionSummary'\n",[70,1264,1265],{"class":72,"line":287},[70,1266,1267],{"class":124},"book.save()\n",[10,1269,1270,1271,1273,1274,1276,1277,1280,1281,1284,1285,1288,1289,1292,1293,1296,1297,54],{},"After ",[14,1272,47],{},", the ",[19,1275,37],{}," table covers the new ",[19,1278,1279],{},"Gross"," column as well, rows are in the new order, and anything that refers to ",[14,1282,1283],{},"Sales[Net]"," keeps working because the table, not an address, is the reference. ",[14,1286,1287],{},"show_totals = True"," adds the totals row below the data. A new table is created with ",[14,1290,1291],{},"tables.add()"," from a range — here the summary written at A1, expanded to its full size — with a name and a style; from then on, other scripts and formulas can refer to it as ",[14,1294,1295],{},"RegionSummary",". Tables in files that are not open in Excel are handled with openpyxl instead, as in ",[50,1298,1300],{"href":1299},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002Fread-an-excel-table-by-name-into-pandas\u002F","Read an Excel Table by Name into pandas",[791,1302,800,1307,800,1310,800,1313,800,1316,800,1323,800,1331,800,1337,800,1340,800,1345,800,1350,800,1355,800,1358,800,1363,800,1368,800,1372,800,1375,800,1379,800,1382,800,1385,800,1391,800,1396,800,1400,800,1404,800,1407,800,1410,800,1416,800,1421,800,1424,800,1428,800,1431,800,1436,800,1443,800,1449,800,1452,800,1455],{"viewBox":1303,"role":794,"ariaLabelledBy":1304,"xmlns":798,"style":799},"4 0 752 160",[1305,1306],"xn-flow-t","xn-flow-d",[802,1308,1309],{"id":1305},"A script that works by name",[806,1311,1312],{"id":1306},"The script reads the TaxRate named cell and the Sales table into pandas, computes gross amounts, writes the DataFrame back into the table with update so the table resizes, writes the total to the NetTotal named cell, and creates a new RegionSummary table from a summary.",[810,1314],{"x":812,"y":813,"width":814,"height":1315,"fill":816},"160",[810,1317],{"x":819,"y":820,"width":1318,"height":1319,"rx":1320,"fill":1321,"stroke":1322,"style":826},"115.2","128.0","12","#e7ebef","var(--line,#cdd5e6)",[828,1324,1326],{"transform":1325},"translate(65.6,37.8) scale(1.000)",[832,1327],{"d":1328,"fill":835,"stroke":1329,"style":1330},"M8 11a4 4 0 1 0 .01 0z M11 13l9-9 M17 7l2 2 M15 9l2 2","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[839,1332,1336],{"x":1333,"y":1334,"style":1335},"77.6","84.2","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Read",[839,1338,25],{"x":1333,"y":1339,"style":1335},"101.8",[839,1341,1344],{"x":1333,"y":1342,"style":1343},"121.2","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","named cell",[72,1346],{"x1":1347,"y1":1348,"x2":1349,"y2":1348,"stroke":825,"style":826},"140.2","80.0","162.2",[1351,1352],"polygon",{"points":1353,"fill":1354},"166.2,80.0 157.2,85.0 157.2,75.0","#5b5cf0",[810,1356],{"x":1357,"y":820,"width":1318,"height":1319,"rx":1320,"fill":824,"stroke":825,"style":826},"171.2",[828,1359,1361],{"transform":1360},"translate(216.8,37.8) scale(1.000)",[832,1362],{"d":878,"fill":835,"stroke":836,"style":1330},[839,1364,1367],{"x":1365,"y":1334,"style":1366},"228.8","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Read Sales",[839,1369,1371],{"x":1365,"y":1370,"style":1343},"103.8","table →",[839,1373,1374],{"x":1365,"y":1342,"style":1343},"DataFrame",[72,1376],{"x1":1377,"y1":1348,"x2":1378,"y2":1348,"stroke":825,"style":826},"291.4","313.4",[1351,1380],{"points":1381,"fill":1354},"317.4,80.0 308.4,85.0 308.4,75.0",[810,1383],{"x":1384,"y":820,"width":1318,"height":1319,"rx":1320,"fill":1321,"stroke":1322,"style":826},"322.4",[828,1386,1388],{"transform":1387},"translate(368.0,46.5) scale(1.000)",[832,1389],{"d":1390,"fill":835,"stroke":1329,"style":1330},"M12 3c-4 0-4 1.6-4 3v2h4.2v1H6c-2 0-3 1.4-3 4s1 4 3 4h2v-2.6c0-1.6 1.3-2.9 2.9-2.9h4.2c1.3 0 2.4-1.1 2.4-2.4V6c0-1.6-1.8-3-5.5-3z M10 5.5h.01 M12 21c4 0 4-1.6 4-3v-2h-4.2v-1H18c2 0 3-1.4 3-4s-1-4-3-4h-2v2.6c0 1.6-1.3 2.9-2.9 2.9H8.9c-1.3 0-2.4 1.1-2.4 2.4V18c0 1.6 1.8 3 5.5 3z M14 18.5h.01",[839,1392,1395],{"x":1393,"y":1394,"style":1335},"380.0","93.0","Compute",[839,1397,1399],{"x":1393,"y":1398,"style":1343},"112.5","pandas",[72,1401],{"x1":1402,"y1":1348,"x2":1403,"y2":1348,"stroke":825,"style":826},"442.6","464.6",[1351,1405],{"points":1406,"fill":1354},"468.6,80.0 459.6,85.0 459.6,75.0",[810,1408],{"x":1409,"y":820,"width":1318,"height":1319,"rx":1320,"fill":871,"stroke":872,"style":826},"473.6",[828,1411,1413],{"transform":1412},"translate(519.2,46.5) scale(1.000)",[832,1414],{"d":1415,"fill":835,"stroke":879,"style":1330},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7",[839,1417,1420],{"x":1418,"y":1394,"style":1419},"531.2","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","table.update(df)",[839,1422,1423],{"x":1418,"y":1398,"style":1343},"table resizes",[72,1425],{"x1":1426,"y1":1348,"x2":1427,"y2":1348,"stroke":825,"style":826},"593.8","615.8",[1351,1429],{"points":1430,"fill":1354},"619.8,80.0 610.8,85.0 610.8,75.0",[810,1432],{"x":1433,"y":820,"width":1318,"height":1319,"rx":1320,"fill":1434,"stroke":1435,"style":826},"624.8","#fdefd8","var(--gold,#b4740a)",[828,1437,1439],{"transform":1438},"translate(670.4,29.0) scale(1.000)",[832,1440],{"d":1441,"fill":835,"stroke":1442,"style":1330},"M5 12.5l4.5 4.5L19 7","var(--gold-ink,#7a4e06)",[839,1444,1448],{"x":1445,"y":1446,"style":1447},"682.4","75.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Write",[839,1450,1451],{"x":1445,"y":1394,"style":1447},"NetTotal",[839,1453,1454],{"x":1445,"y":1398,"style":1343},"named output",[839,1456,1458],{"x":1445,"y":1457,"style":1343},"130.0","cell",[56,1460,1462],{"id":1461},"naming-conventions-that-help","Naming conventions that help",[10,1464,1465,1466,26,1468,26,1471,1473,1474,1477,1478,1481,1482,26,1484,26,1487,1490,1491,1494],{},"Names are only as useful as they are predictable. A few conventions make workbooks easier to script and to read. Give inputs and outputs names that say what they hold — ",[14,1467,25],{},[14,1469,1470],{},"FxEurUsd",[14,1472,29],{}," — rather than positions such as ",[14,1475,1476],{},"Cell_B7",". Keep names free of spaces (Excel does not allow them) and avoid names that look like cell addresses, such as ",[14,1479,1480],{},"FX1",", which Excel rejects because it is a column-and-row reference. Name tables after the records they hold, in the plural — ",[14,1483,37],{},[14,1485,1486],{},"Customers",[14,1488,1489],{},"Rates"," — so formulas such as ",[14,1492,1493],{},"=SUM(Sales[Net])"," read like sentences. And keep a short list of the names and tables a script relies on at the top of the script, which is exactly what the check below uses.",[56,1496,1498],{"id":1497},"check-the-names-a-script-depends-on","Check the names a script depends on",[10,1500,1501,1502,1504],{},"A script that works by name has a new failure mode: someone deletes or renames ",[14,1503,25],{},", and the script fails half-way through with an unhelpful error. Check the names and tables the script needs before it changes anything. The check can run against the file with openpyxl — no Excel needed — so it also works in tests and on servers:",[61,1506,1508],{"className":111,"code":1507,"language":113,"meta":66,"style":66},"from openpyxl import load_workbook\n\nREQUIRED_NAMES = {\"TaxRate\", \"NetTotal\"}\nREQUIRED_TABLES = {\"Data\": {\"Sales\"}}\n\ndef missing_objects(path):\n    wb = load_workbook(path)\n    problems = [f\"name {n} is missing\" for n in sorted(REQUIRED_NAMES - set(wb.defined_names))]\n    for sheet, tables in REQUIRED_TABLES.items():\n        if sheet not in wb.sheetnames:\n            problems.append(f\"sheet {sheet} is missing\")\n            continue\n        problems += [f\"table {t} is missing on {sheet}\" for t in sorted(tables - set(wb[sheet].tables))]\n    return problems\n\nprint(\"before:\", missing_objects(\"names_and_tables.xlsx\") or \"all present\")\nwb = load_workbook(\"names_and_tables.xlsx\")\ndel wb.defined_names[\"TaxRate\"]\nwb.save(\"broken.xlsx\")\nprint(\"after deleting TaxRate:\", missing_objects(\"broken.xlsx\"))\n",[14,1509,1510,1521,1525,1545,1564,1568,1580,1590,1642,1658,1675,1696,1701,1755,1763,1767,1792,1805,1817,1826],{"__ignoreMap":66},[70,1511,1512,1514,1516,1518],{"class":72,"line":73},[70,1513,121],{"class":120},[70,1515,125],{"class":124},[70,1517,128],{"class":120},[70,1519,1520],{"class":124}," load_workbook\n",[70,1522,1523],{"class":72,"line":134},[70,1524,164],{"emptyLinePlaceholder":163},[70,1526,1527,1530,1533,1536,1538,1540,1542],{"class":72,"line":147},[70,1528,1529],{"class":226},"REQUIRED_NAMES",[70,1531,1532],{"class":120}," =",[70,1534,1535],{"class":124}," {",[70,1537,261],{"class":80},[70,1539,26],{"class":124},[70,1541,292],{"class":80},[70,1543,1544],{"class":124},"}\n",[70,1546,1547,1550,1552,1554,1556,1559,1561],{"class":72,"line":160},[70,1548,1549],{"class":226},"REQUIRED_TABLES",[70,1551,1532],{"class":120},[70,1553,1535],{"class":124},[70,1555,330],{"class":80},[70,1557,1558],{"class":124},": {",[70,1560,441],{"class":80},[70,1562,1563],{"class":124},"}}\n",[70,1565,1566],{"class":72,"line":167},[70,1567,164],{"emptyLinePlaceholder":163},[70,1569,1570,1573,1577],{"class":72,"line":179},[70,1571,1572],{"class":120},"def",[70,1574,1576],{"class":1575},"s_Opv"," missing_objects",[70,1578,1579],{"class":124},"(path):\n",[70,1581,1582,1585,1587],{"class":72,"line":190},[70,1583,1584],{"class":124},"    wb ",[70,1586,173],{"class":120},[70,1588,1589],{"class":124}," load_workbook(path)\n",[70,1591,1592,1595,1597,1600,1603,1606,1610,1613,1616,1619,1622,1624,1626,1629,1631,1633,1636,1639],{"class":72,"line":201},[70,1593,1594],{"class":124},"    problems ",[70,1596,173],{"class":120},[70,1598,1599],{"class":124}," [",[70,1601,1602],{"class":120},"f",[70,1604,1605],{"class":80},"\"name ",[70,1607,1609],{"class":1608},"sSjpA","{",[70,1611,1612],{"class":124},"n",[70,1614,1615],{"class":1608},"}",[70,1617,1618],{"class":80}," is missing\"",[70,1620,1621],{"class":120}," for",[70,1623,663],{"class":124},[70,1625,366],{"class":120},[70,1627,1628],{"class":226}," sorted",[70,1630,510],{"class":124},[70,1632,1529],{"class":226},[70,1634,1635],{"class":120}," -",[70,1637,1638],{"class":226}," set",[70,1640,1641],{"class":124},"(wb.defined_names))]\n",[70,1643,1644,1647,1650,1652,1655],{"class":72,"line":230},[70,1645,1646],{"class":120},"    for",[70,1648,1649],{"class":124}," sheet, tables ",[70,1651,366],{"class":120},[70,1653,1654],{"class":226}," REQUIRED_TABLES",[70,1656,1657],{"class":124},".items():\n",[70,1659,1660,1663,1666,1669,1672],{"class":72,"line":255},[70,1661,1662],{"class":120},"        if",[70,1664,1665],{"class":124}," sheet ",[70,1667,1668],{"class":120},"not",[70,1670,1671],{"class":120}," in",[70,1673,1674],{"class":124}," wb.sheetnames:\n",[70,1676,1677,1680,1682,1685,1687,1690,1692,1694],{"class":72,"line":287},[70,1678,1679],{"class":124},"            problems.append(",[70,1681,1602],{"class":120},[70,1683,1684],{"class":80},"\"sheet ",[70,1686,1609],{"class":1608},[70,1688,1689],{"class":124},"sheet",[70,1691,1615],{"class":1608},[70,1693,1618],{"class":80},[70,1695,284],{"class":124},[70,1697,1698],{"class":72,"line":314},[70,1699,1700],{"class":120},"            continue\n",[70,1702,1703,1706,1709,1711,1713,1716,1718,1721,1723,1726,1728,1730,1732,1735,1737,1740,1742,1744,1747,1750,1752],{"class":72,"line":319},[70,1704,1705],{"class":124},"        problems ",[70,1707,1708],{"class":120},"+=",[70,1710,1599],{"class":124},[70,1712,1602],{"class":120},[70,1714,1715],{"class":80},"\"table ",[70,1717,1609],{"class":1608},[70,1719,1720],{"class":124},"t",[70,1722,1615],{"class":1608},[70,1724,1725],{"class":80}," is missing on ",[70,1727,1609],{"class":1608},[70,1729,1689],{"class":124},[70,1731,1615],{"class":1608},[70,1733,1734],{"class":80},"\"",[70,1736,1621],{"class":120},[70,1738,1739],{"class":124}," t ",[70,1741,366],{"class":120},[70,1743,1628],{"class":226},[70,1745,1746],{"class":124},"(tables ",[70,1748,1749],{"class":120},"-",[70,1751,1638],{"class":226},[70,1753,1754],{"class":124},"(wb[sheet].tables))]\n",[70,1756,1757,1760],{"class":72,"line":335},[70,1758,1759],{"class":120},"    return",[70,1761,1762],{"class":124}," problems\n",[70,1764,1765],{"class":72,"line":357},[70,1766,164],{"emptyLinePlaceholder":163},[70,1768,1769,1771,1773,1776,1779,1781,1784,1787,1790],{"class":72,"line":419},[70,1770,507],{"class":226},[70,1772,510],{"class":124},[70,1774,1775],{"class":80},"\"before:\"",[70,1777,1778],{"class":124},", missing_objects(",[70,1780,499],{"class":80},[70,1782,1783],{"class":124},") ",[70,1785,1786],{"class":120},"or",[70,1788,1789],{"class":80}," \"all present\"",[70,1791,284],{"class":124},[70,1793,1794,1796,1798,1801,1803],{"class":72,"line":425},[70,1795,170],{"class":124},[70,1797,173],{"class":120},[70,1799,1800],{"class":124}," load_workbook(",[70,1802,499],{"class":80},[70,1804,284],{"class":124},[70,1806,1807,1810,1813,1815],{"class":72,"line":456},[70,1808,1809],{"class":120},"del",[70,1811,1812],{"class":124}," wb.defined_names[",[70,1814,261],{"class":80},[70,1816,637],{"class":124},[70,1818,1819,1821,1824],{"class":72,"line":487},[70,1820,496],{"class":124},[70,1822,1823],{"class":80},"\"broken.xlsx\"",[70,1825,284],{"class":124},[70,1827,1828,1830,1832,1835,1837,1839],{"class":72,"line":493},[70,1829,507],{"class":226},[70,1831,510],{"class":124},[70,1833,1834],{"class":80},"\"after deleting TaxRate:\"",[70,1836,1778],{"class":124},[70,1838,1823],{"class":80},[70,1840,1841],{"class":124},"))\n",[10,1843,1844,1845,1847,1848,1851,1852,1855],{},"The original workbook has everything the script needs; the copy with ",[14,1846,25],{}," deleted is caught with a message that names the problem. In an xlwings script, run the same comparison against ",[14,1849,1850],{},"[n.name for n in book.names]"," and the sheet's ",[14,1853,1854],{},"tables"," before the first write, and stop with that message rather than half-updating the workbook. Templates that people edit benefit most: the check turns \"the macro broke\" into \"someone deleted the TaxRate name\", which they can fix themselves.",[791,1857,800,1862,800,1865,800,1868,800,1871,800,1875,800,1881,800,1884,800,1888,800,1892,800,1895,800,1898,800,1906,800,1911,800,1915,800,1920,800,1924,800,1928,800,1930,800,1933,800,1937,800,1940,800,1943,800,1949,800,1952],{"viewBox":1858,"role":794,"ariaLabelledBy":1859,"xmlns":798,"style":799},"4 0 752 272",[1860,1861],"xn-check-t","xn-check-d",[802,1863,1864],{"id":1860},"Before the script writes anything",[806,1866,1867],{"id":1861},"List the workbook's names and each sheet's tables and compare them with what the script needs. If everything is present the script proceeds; if a name, table or sheet is missing it stops with a message naming the missing object, before changing the workbook.",[810,1869],{"x":812,"y":813,"width":814,"height":1870,"fill":816},"272",[810,1872],{"x":1873,"y":820,"width":1874,"height":1446,"rx":1320,"fill":824,"stroke":825,"style":826},"201.8","356.3",[828,1876,1878],{"transform":1877},"translate(368.0,29.0) scale(1.000)",[832,1879],{"d":1880,"fill":835,"stroke":836,"style":1330},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5",[839,1882,1883],{"x":1393,"y":1446,"style":1366},"Are all required names and tables present?",[72,1885],{"x1":1393,"y1":1886,"x2":1393,"y2":1887,"stroke":825,"style":826},"91.5","111.5",[72,1889],{"x1":1890,"y1":1887,"x2":1891,"y2":1887,"stroke":825,"style":826},"196.0","564.0",[72,1893],{"x1":1890,"y1":1887,"x2":1890,"y2":1894,"stroke":825,"style":826},"157.5",[1351,1896],{"points":1897,"fill":1354},"196.0,161.5 191.0,152.5 201.0,152.5",[810,1899],{"x":1900,"y":1901,"width":1902,"height":1903,"rx":1904,"fill":816,"stroke":1322,"style":1905},"176.4","121.5","39.2","21.0","10","stroke-width:1.2px",[839,1907,1910],{"x":1890,"y":1908,"style":1909},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","yes",[810,1912],{"x":819,"y":1913,"width":1914,"height":1394,"rx":1320,"fill":871,"stroke":872,"style":826},"163.5","352.0",[828,1916,1918],{"transform":1917},"translate(184.0,176.5) scale(1.000)",[832,1919],{"d":1441,"fill":835,"stroke":879,"style":1330},[839,1921,1923],{"x":1890,"y":1922,"style":1419},"223.0","run the script",[839,1925,1927],{"x":1890,"y":1926,"style":1343},"242.5","works by name",[72,1929],{"x1":1891,"y1":1887,"x2":1891,"y2":1894,"stroke":825,"style":826},[1351,1931],{"points":1932,"fill":1354},"564.0,161.5 559.0,152.5 569.0,152.5",[810,1934],{"x":1935,"y":1901,"width":1936,"height":1903,"rx":1904,"fill":816,"stroke":1322,"style":1905},"547.5","32.9",[839,1938,1939],{"x":1891,"y":1908,"style":1909},"no",[810,1941],{"x":1942,"y":1913,"width":1914,"height":1394,"rx":1320,"fill":1434,"stroke":1435,"style":826},"388.0",[828,1944,1946],{"transform":1945},"translate(552.0,176.5) scale(1.000)",[832,1947],{"d":1948,"fill":835,"stroke":1442,"style":1330},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4",[839,1950,1951],{"x":1891,"y":1922,"style":1447},"stop with a clear message",[839,1953,1954],{"x":1891,"y":1926,"style":1343},"e.g. name TaxRate is missing",[56,1956,1958],{"id":1957},"common-pitfalls","Common pitfalls",[1960,1961,1962,1970,1985,1995,2004],"ul",{},[1963,1964,1965,1969],"li",{},[1966,1967,1968],"strong",{},"Hard-coded addresses."," Use names and tables so layout changes do not break scripts.",[1963,1971,1972,1981,1982,54],{},[1966,1973,1974,1975,1977,1978,54],{},"Forgetting the ",[14,1976,173],{}," in ",[14,1979,1980],{},"names.add()"," Definitions are written like formulas: ",[14,1983,1984],{},"=Sheet!$B$2",[1963,1986,1987,1990,1991,1994],{},[1966,1988,1989],{},"Writing a DataFrame over a table's range."," Use ",[14,1992,1993],{},"table.update()"," so the table resizes.",[1963,1996,1997,2000,2001,54],{},[1966,1998,1999],{},"Losing the first column."," Read tables with ",[14,2002,2003],{},"options(pd.DataFrame, index=False)",[1963,2005,2006,2009],{},[1966,2007,2008],{},"Clashing names across sheets."," Use sheet-scoped names for per-sheet values.",[56,2011,2013],{"id":2012},"conclusion","Conclusion",[10,2015,2016,2017,2019,2020,2023,2024,542,2026,2029,2030,2033,2034,2037,2038,2041,2042,2044],{},"In xlwings, use names wherever you would use addresses: ",[14,2018,749],{}," or ",[14,2021,2022],{},"book.names[\"TaxRate\"].refers_to_range"," for single inputs and outputs, ",[14,2025,772],{},[14,2027,2028],{},"sheet.names.add()"," to create them, and ",[14,2031,2032],{},"sheet.tables[\"Sales\"]"," for blocks of records. Read a table with ",[14,2035,2036],{},"table.range.options(pd.DataFrame, index=False)",", write it back with ",[14,2039,2040],{},"table.update(df, index=False)"," so it resizes, and create new tables with ",[14,2043,1291],{},". Scripts written this way keep working when people rearrange the workbook.",[56,2046,2048],{"id":2047},"frequently-asked-questions","Frequently asked questions",[10,2050,2051,2054,2055,2057],{},[1966,2052,2053],{},"How do I read a named range with xlwings?","\nUse the name as an address, sheet",[70,2056,261],{},".value, or look it up through book.names and read the value of its refers_to_range.",[10,2059,2060,2063],{},[1966,2061,2062],{},"How do I create a named range with xlwings?","\nCall book.names.add(\"Name\", \"=Sheet!$B$2\") for a workbook-level name, or sheet.names.add for a name scoped to one sheet.",[10,2065,2066,2069,2070,2073],{},[1966,2067,2068],{},"How do I read an Excel table into pandas with xlwings?","\nGet the table with sheet.tables",[70,2071,2072],{},"\"Name\""," and read table.range.options(pd.DataFrame, index=False).value.",[10,2075,2076,2079],{},[1966,2077,2078],{},"How do I write a DataFrame back into an Excel table with xlwings?","\nCall table.update(df, index=False); it writes the data and resizes the table to the DataFrame.",[56,2081,2083],{"id":2082},"related","Related",[1960,2085,2086,2092,2099,2106],{},[1963,2087,2088,2089,2091],{},"Up one level: ",[50,2090,53],{"href":52}," — live Excel from Python.",[1963,2093,2094,2098],{},[50,2095,2097],{"href":2096},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-named-range-into-pandas\u002F","Read a Named Range into pandas"," — named ranges from closed files.",[1963,2100,2101,2105],{},[50,2102,2104],{"href":2103},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fread-and-write-a-live-excel-workbook-with-xlwings\u002F","Read and Write a Live Excel Workbook with xlwings"," — the basics.",[1963,2107,2108,2112],{},[50,2109,2111],{"href":2110},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002Fcreate-an-excel-table-with-python\u002F","Create an Excel Table with Python"," — tables with openpyxl.",[2114,2115,2116],"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 .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}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":66,"searchDepth":134,"depth":134,"links":2118},[2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,2129],{"id":58,"depth":134,"text":59},{"id":107,"depth":134,"text":108},{"id":553,"depth":134,"text":554},{"id":903,"depth":134,"text":904},{"id":1052,"depth":134,"text":1053},{"id":1461,"depth":134,"text":1462},{"id":1497,"depth":134,"text":1498},{"id":1957,"depth":134,"text":1958},{"id":2012,"depth":134,"text":2013},{"id":2047,"depth":134,"text":2048},{"id":2082,"depth":134,"text":2083},"2026-10-02","Address data in a live Excel workbook by name instead of by cell address with xlwings: read and write named ranges for inputs and results, list, add and remove names at workbook and sheet scope, read an Excel table into pandas, write a DataFrame back into the table with update() so it resizes, add totals, and create new tables from Python.","md",[2134,2136,2138,2140],{"q":2053,"a":2135},"Use the name as an address, sheet[\"TaxRate\"].value, or look it up through book.names and read the value of its refers_to_range.",{"q":2062,"a":2137},"Call book.names.add(\"Name\", \"=Sheet!$B$2\") for a workbook-level name, or sheet.names.add for a name scoped to one sheet.",{"q":2068,"a":2139},"Get the table with sheet.tables[\"Name\"] and read table.range.options(pd.DataFrame, index=False).value.",{"q":2078,"a":2141},"Call table.update(df, index=False); it writes the data and resizes the table to the DataFrame.","named ranges and tables in xlwings",null,{"breadcrumb":2145},[2146,2149,2152],{"name":2147,"item":2148},"Home","\u002F",{"name":2150,"item":2151},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":2153,"item":52},"Automating Excel With xlwings: The Basics","\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fwork-with-named-ranges-and-tables-in-xlwings",{"title":5,"description":2156},"xlwings names and tables: book.names, refers_to_range, sheet-scoped names, sheet.tables, data_body_range, reading tables into pandas, Table.update to resize with a DataFrame, show_totals and tables.add.","work-with-named-ranges-and-tables-in-xlwings","getting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fwork-with-named-ranges-and-tables-in-xlwings\u002Findex",[2160],"xlwings","how-to","eO5lO9btBIauhTekpkhnzGGtLiV7JvSKRm1Ohl7BMjU",[2164,2168],{"title":2165,"path":2166,"stem":2167,"children":-1},"Speed Up xlwings with Bulk Reads and Writes","\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fspeed-up-xlwings-with-bulk-reads-and-writes","getting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fspeed-up-xlwings-with-bulk-reads-and-writes\u002Findex",{"title":2169,"path":2170,"stem":2171,"children":-1},"xlwings: Run a VBA Macro From Python (Example)","\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fxlwings-run-macro-from-python-example","getting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fxlwings-run-macro-from-python-example\u002Findex",[2173,2175],{"path":2174,"title":2153},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics",{"path":2176,"title":2150},"\u002Fgetting-started-with-python-excel-automation",[],[2179,2182,2185,2189,2191,2194],{"path":2180,"title":2181,"kind":2161},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Ftest-win32com-and-xlwings-code-without-excel","Test win32com and xlwings Code Without Excel",{"path":2183,"title":2184,"kind":2161},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python","Automate Excel on macOS with Python",{"path":2186,"title":2187,"kind":2188},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fxlwings-vs-pywin32-for-excel-automation","xlwings vs pywin32 for Excel Automation","compare",{"path":2190,"title":1049,"kind":2161},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fcontrol-how-xlwings-converts-dataframes-and-ranges",{"path":2192,"title":2193,"kind":2161},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fformat-cells-in-a-live-workbook-with-xlwings","Format Cells in a Live Workbook with xlwings",{"path":2195,"title":2196,"kind":2161},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Finsert-a-matplotlib-plot-into-a-live-workbook-with-xlwings","Insert a matplotlib Plot into a Live Workbook with xlwings",1790972057081]