[{"data":1,"prerenderedAt":1437},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation":1403,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation":1411,"children:\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation":1416,"related:\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation":1417},{"id":4,"title":5,"body":6,"dateModified":1369,"datePublished":1369,"description":1370,"extension":1371,"faq":1372,"keyword":1381,"kind":1382,"meta":1383,"navigation":336,"path":1392,"seo":1393,"slug":1396,"stem":1397,"topics":1398,"type":1401,"__hash__":1402},"docs\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation\u002Findex.md","Python vs VBA for Excel Automation",{"type":7,"value":8,"toc":1358},"minimark",[9,19,179,184,187,294,297,478,795,803,807,1017,1020,1036,1042,1056,1067,1071,1205,1213,1217,1224,1236,1240,1247,1251,1286,1290,1293,1297,1303,1309,1315,1321,1325,1354],[10,11,12,13,18],"p",{},"VBA has automated Excel for thirty years and lives inside the workbook; Python arrived later and works mostly from the outside. They overlap, which is why the question comes up on every team that has both skills — but they are good at different things, and the right answer is often \"both, for different parts of the job\". This guide, part of ",[14,15,17],"a",{"href":16},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002F","Choosing a Python Excel Library",", compares them on the dimensions that decide real projects and builds the same small report in each.",[20,21,29,30,29,34,29,38,29,46,29,56,29,67,29,74,29,81,29,87,29,95,29,99,29,104,29,108,29,114,29,118,29,125,29,130,29,137,29,142,29,146,29,150,29,155,29,158,29,163,29,166,29,171,29,174],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"4 0 752 233","img",[25,26],"vba-where-t","vba-where-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  ",[31,32,33],"title",{"id":25},"Where VBA and Python run in relation to Excel",[35,36,37],"desc",{"id":26},"VBA runs inside the Excel application, stored in a macro-enabled workbook, and reacts to what the user does. Python usually runs outside Excel, reading and writing workbook files without Excel installed, or drives a running Excel through xlwings or COM on Windows.",[39,40],"rect",{"x":41,"y":42,"width":43,"height":44,"fill":45},"4","0","752","233","#ffffff",[39,47],{"x":48,"y":49,"width":50,"height":51,"rx":52,"fill":53,"stroke":54,"style":55},"20.0","16.0","351.0","201.0","14","#fdefd8","var(--gold,#b4740a)","stroke-width:2px",[57,58,60],"g",{"transform":59},"translate(182.5,29.0) scale(1.083)",[61,62],"path",{"d":63,"fill":64,"stroke":65,"style":66},"M3 5.5l8-1.2v7.2H3z M13 4l8-1.2v8.7h-8z M3 13.5h8v7.2l-8-1.2z M13 13.5h8v8.7l-8-1.2z","none","var(--gold-ink,#7a4e06)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[68,69,73],"text",{"x":70,"y":71,"style":72},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","VBA",[75,76],"line",{"x1":77,"y1":78,"x2":79,"y2":78,"stroke":54,"style":80},"36.0","91.0","355.0","stroke-width:1px",[68,82,86],{"x":83,"y":84,"style":85},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","runs inside Excel",[57,88,90],{"transform":89},"translate(38.5,99.5) scale(0.625)",[61,91],{"d":92,"fill":64,"stroke":93,"style":94},"M5 12.5l4.5 4.5L19 7","var(--teal,#0f9488)","stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[68,96,98],{"x":83,"y":97,"style":85},"137.0","buttons, events, forms",[57,100,102],{"transform":101},"translate(38.5,125.5) scale(0.625)",[61,103],{"d":92,"fill":64,"stroke":93,"style":94},[68,105,107],{"x":83,"y":106,"style":85},"163.0","stored in .xlsm files",[57,109,111],{"transform":110},"translate(38.5,151.5) scale(0.625)",[61,112],{"d":113,"fill":64,"stroke":54,"style":94},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4",[68,115,117],{"x":83,"y":116,"style":85},"189.0","desktop Excel only",[57,119,121],{"transform":120},"translate(38.5,177.5) scale(0.625)",[61,122],{"d":123,"fill":64,"stroke":124,"style":94},"M6 6l12 12 M18 6L6 18","var(--accent,#f43f8f)",[39,126],{"x":127,"y":49,"width":50,"height":51,"rx":52,"fill":128,"stroke":129,"style":55},"389.0","#f0f4ff","var(--brand,#5b5cf0)",[57,131,133],{"transform":132},"translate(551.5,29.0) scale(1.083)",[61,134],{"d":135,"fill":64,"stroke":136,"style":66},"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","var(--brand-strong,#4338ca)",[68,138,141],{"x":139,"y":71,"style":140},"564.5","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Python",[75,143],{"x1":144,"y1":78,"x2":145,"y2":78,"stroke":129,"style":80},"405.0","724.0",[68,147,149],{"x":148,"y":84,"style":85},"429.0","runs outside Excel",[57,151,153],{"transform":152},"translate(407.5,99.5) scale(0.625)",[61,154],{"d":92,"fill":64,"stroke":93,"style":94},[68,156,157],{"x":148,"y":97,"style":85},"no Excel needed to write files",[57,159,161],{"transform":160},"translate(407.5,125.5) scale(0.625)",[61,162],{"d":92,"fill":64,"stroke":93,"style":94},[68,164,165],{"x":148,"y":106,"style":85},"servers, schedules, pipelines",[57,167,169],{"transform":168},"translate(407.5,151.5) scale(0.625)",[61,170],{"d":92,"fill":64,"stroke":93,"style":94},[68,172,173],{"x":148,"y":116,"style":85},"drives Excel via xlwings\u002FCOM",[57,175,177],{"transform":176},"translate(407.5,177.5) scale(0.625)",[61,178],{"d":113,"fill":64,"stroke":54,"style":94},[180,181,183],"h2",{"id":182},"the-same-task-in-both-languages","The same task in both languages",[10,185,186],{},"The task: a sheet of orders; highlight every order over 1,000 and write a total per region to a summary sheet. First in VBA, as a macro stored in the workbook:",[188,189,194],"pre",{"className":190,"code":191,"language":192,"meta":193,"style":193},"language-vb shiki shiki-themes github-light github-dark-high-contrast","Sub BuildSummary()\n    Dim ws As Worksheet, sm As Worksheet, r As Long, last As Long\n    Dim totals As Object: Set totals = CreateObject(\"Scripting.Dictionary\")\n    Set ws = ThisWorkbook.Sheets(\"Orders\")\n    Set sm = ThisWorkbook.Sheets(\"Summary\")\n    last = ws.Cells(ws.Rows.Count, \"A\").End(xlUp).Row\n    For r = 2 To last\n        If ws.Cells(r, 3).Value > 1000 Then ws.Range(ws.Cells(r, 1), ws.Cells(r, 3)).Interior.Color = RGB(252, 233, 233)\n        totals(ws.Cells(r, 2).Value) = totals(ws.Cells(r, 2).Value) + ws.Cells(r, 3).Value\n    Next r\n    sm.Range(\"A1:B1\").Value = Array(\"Region\", \"Total\")\n    Dim k, i As Long: i = 2\n    For Each k In totals.Keys\n        sm.Cells(i, 1).Value = k: sm.Cells(i, 2).Value = totals(k): i = i + 1\n    Next k\nEnd Sub\n","vb","",[195,196,197,204,210,216,222,228,234,240,246,252,258,264,270,276,282,288],"code",{"__ignoreMap":193},[198,199,201],"span",{"class":75,"line":200},1,[198,202,203],{},"Sub BuildSummary()\n",[198,205,207],{"class":75,"line":206},2,[198,208,209],{},"    Dim ws As Worksheet, sm As Worksheet, r As Long, last As Long\n",[198,211,213],{"class":75,"line":212},3,[198,214,215],{},"    Dim totals As Object: Set totals = CreateObject(\"Scripting.Dictionary\")\n",[198,217,219],{"class":75,"line":218},4,[198,220,221],{},"    Set ws = ThisWorkbook.Sheets(\"Orders\")\n",[198,223,225],{"class":75,"line":224},5,[198,226,227],{},"    Set sm = ThisWorkbook.Sheets(\"Summary\")\n",[198,229,231],{"class":75,"line":230},6,[198,232,233],{},"    last = ws.Cells(ws.Rows.Count, \"A\").End(xlUp).Row\n",[198,235,237],{"class":75,"line":236},7,[198,238,239],{},"    For r = 2 To last\n",[198,241,243],{"class":75,"line":242},8,[198,244,245],{},"        If ws.Cells(r, 3).Value > 1000 Then ws.Range(ws.Cells(r, 1), ws.Cells(r, 3)).Interior.Color = RGB(252, 233, 233)\n",[198,247,249],{"class":75,"line":248},9,[198,250,251],{},"        totals(ws.Cells(r, 2).Value) = totals(ws.Cells(r, 2).Value) + ws.Cells(r, 3).Value\n",[198,253,255],{"class":75,"line":254},10,[198,256,257],{},"    Next r\n",[198,259,261],{"class":75,"line":260},11,[198,262,263],{},"    sm.Range(\"A1:B1\").Value = Array(\"Region\", \"Total\")\n",[198,265,267],{"class":75,"line":266},12,[198,268,269],{},"    Dim k, i As Long: i = 2\n",[198,271,273],{"class":75,"line":272},13,[198,274,275],{},"    For Each k In totals.Keys\n",[198,277,279],{"class":75,"line":278},14,[198,280,281],{},"        sm.Cells(i, 1).Value = k: sm.Cells(i, 2).Value = totals(k): i = i + 1\n",[198,283,285],{"class":75,"line":284},15,[198,286,287],{},"    Next k\n",[198,289,291],{"class":75,"line":290},16,[198,292,293],{},"End Sub\n",[10,295,296],{},"Then in Python, working on the file without Excel — first some sample data so the example runs as written:",[188,298,302],{"className":299,"code":300,"language":301,"meta":193,"style":193},"language-python shiki shiki-themes github-light github-dark-high-contrast","import numpy as np\nimport pandas as pd\n\nrng = np.random.default_rng(3)\norders = pd.DataFrame({\n    \"order_id\": np.arange(1001, 1101),\n    \"region\": rng.choice([\"North\", \"South\", \"East\", \"West\"], 100),\n    \"amount\": rng.integers(100, 2500, 100),\n})\norders.to_excel(\"orders.xlsx\", sheet_name=\"Orders\", index=False)\n","python",[195,303,304,320,332,338,356,366,387,421,442,447],{"__ignoreMap":193},[198,305,306,310,314,317],{"class":75,"line":200},[198,307,309],{"class":308},"s-kum","import",[198,311,313],{"class":312},"skGVy"," numpy ",[198,315,316],{"class":308},"as",[198,318,319],{"class":312}," np\n",[198,321,322,324,327,329],{"class":75,"line":206},[198,323,309],{"class":308},[198,325,326],{"class":312}," pandas ",[198,328,316],{"class":308},[198,330,331],{"class":312}," pd\n",[198,333,334],{"class":75,"line":212},[198,335,337],{"emptyLinePlaceholder":336},true,"\n",[198,339,340,343,346,349,353],{"class":75,"line":218},[198,341,342],{"class":312},"rng ",[198,344,345],{"class":308},"=",[198,347,348],{"class":312}," np.random.default_rng(",[198,350,352],{"class":351},"sP0c6","3",[198,354,355],{"class":312},")\n",[198,357,358,361,363],{"class":75,"line":224},[198,359,360],{"class":312},"orders ",[198,362,345],{"class":308},[198,364,365],{"class":312}," pd.DataFrame({\n",[198,367,368,372,375,378,381,384],{"class":75,"line":230},[198,369,371],{"class":370},"srMev","    \"order_id\"",[198,373,374],{"class":312},": np.arange(",[198,376,377],{"class":351},"1001",[198,379,380],{"class":312},", ",[198,382,383],{"class":351},"1101",[198,385,386],{"class":312},"),\n",[198,388,389,392,395,398,400,403,405,408,410,413,416,419],{"class":75,"line":236},[198,390,391],{"class":370},"    \"region\"",[198,393,394],{"class":312},": rng.choice([",[198,396,397],{"class":370},"\"North\"",[198,399,380],{"class":312},[198,401,402],{"class":370},"\"South\"",[198,404,380],{"class":312},[198,406,407],{"class":370},"\"East\"",[198,409,380],{"class":312},[198,411,412],{"class":370},"\"West\"",[198,414,415],{"class":312},"], ",[198,417,418],{"class":351},"100",[198,420,386],{"class":312},[198,422,423,426,429,431,433,436,438,440],{"class":75,"line":242},[198,424,425],{"class":370},"    \"amount\"",[198,427,428],{"class":312},": rng.integers(",[198,430,418],{"class":351},[198,432,380],{"class":312},[198,434,435],{"class":351},"2500",[198,437,380],{"class":312},[198,439,418],{"class":351},[198,441,386],{"class":312},[198,443,444],{"class":75,"line":248},[198,445,446],{"class":312},"})\n",[198,448,449,452,455,457,461,463,466,468,471,473,476],{"class":75,"line":254},[198,450,451],{"class":312},"orders.to_excel(",[198,453,454],{"class":370},"\"orders.xlsx\"",[198,456,380],{"class":312},[198,458,460],{"class":459},"sa561","sheet_name",[198,462,345],{"class":308},[198,464,465],{"class":370},"\"Orders\"",[198,467,380],{"class":312},[198,469,470],{"class":459},"index",[198,472,345],{"class":308},[198,474,475],{"class":351},"False",[198,477,355],{"class":312},[188,479,481],{"className":299,"code":480,"language":301,"meta":193,"style":193},"from openpyxl import load_workbook\nfrom openpyxl.formatting.rule import FormulaRule\nfrom openpyxl.styles import PatternFill\n\ndata = pd.read_excel(\"orders.xlsx\", sheet_name=\"Orders\")\ntotals = data.groupby(\"region\", as_index=False)[\"amount\"].sum().rename(columns={\"amount\": \"total\"})\n\nwith pd.ExcelWriter(\"orders.xlsx\", mode=\"a\", engine=\"openpyxl\", if_sheet_exists=\"replace\") as writer:\n    totals.to_excel(writer, sheet_name=\"Summary\", index=False)\n    ws = writer.book[\"Orders\"]\n    last = ws.max_row\n    ws.conditional_formatting.add(\n        f\"A2:C{last}\",\n        FormulaRule(formula=[\"$C2>1000\"], fill=PatternFill(\"solid\", fgColor=\"FCE9E9\")),\n    )\n\nprint(pd.read_excel(\"orders.xlsx\", sheet_name=\"Summary\"))\n",[195,482,483,496,508,520,524,546,595,599,647,669,684,694,699,722,764,769,773],{"__ignoreMap":193},[198,484,485,488,491,493],{"class":75,"line":200},[198,486,487],{"class":308},"from",[198,489,490],{"class":312}," openpyxl ",[198,492,309],{"class":308},[198,494,495],{"class":312}," load_workbook\n",[198,497,498,500,503,505],{"class":75,"line":206},[198,499,487],{"class":308},[198,501,502],{"class":312}," openpyxl.formatting.rule ",[198,504,309],{"class":308},[198,506,507],{"class":312}," FormulaRule\n",[198,509,510,512,515,517],{"class":75,"line":212},[198,511,487],{"class":308},[198,513,514],{"class":312}," openpyxl.styles ",[198,516,309],{"class":308},[198,518,519],{"class":312}," PatternFill\n",[198,521,522],{"class":75,"line":218},[198,523,337],{"emptyLinePlaceholder":336},[198,525,526,529,531,534,536,538,540,542,544],{"class":75,"line":224},[198,527,528],{"class":312},"data ",[198,530,345],{"class":308},[198,532,533],{"class":312}," pd.read_excel(",[198,535,454],{"class":370},[198,537,380],{"class":312},[198,539,460],{"class":459},[198,541,345],{"class":308},[198,543,465],{"class":370},[198,545,355],{"class":312},[198,547,548,551,553,556,559,561,564,566,568,571,574,577,580,582,585,587,590,593],{"class":75,"line":230},[198,549,550],{"class":312},"totals ",[198,552,345],{"class":308},[198,554,555],{"class":312}," data.groupby(",[198,557,558],{"class":370},"\"region\"",[198,560,380],{"class":312},[198,562,563],{"class":459},"as_index",[198,565,345],{"class":308},[198,567,475],{"class":351},[198,569,570],{"class":312},")[",[198,572,573],{"class":370},"\"amount\"",[198,575,576],{"class":312},"].sum().rename(",[198,578,579],{"class":459},"columns",[198,581,345],{"class":308},[198,583,584],{"class":312},"{",[198,586,573],{"class":370},[198,588,589],{"class":312},": ",[198,591,592],{"class":370},"\"total\"",[198,594,446],{"class":312},[198,596,597],{"class":75,"line":236},[198,598,337],{"emptyLinePlaceholder":336},[198,600,601,604,607,609,611,614,616,619,621,624,626,629,631,634,636,639,642,644],{"class":75,"line":242},[198,602,603],{"class":308},"with",[198,605,606],{"class":312}," pd.ExcelWriter(",[198,608,454],{"class":370},[198,610,380],{"class":312},[198,612,613],{"class":459},"mode",[198,615,345],{"class":308},[198,617,618],{"class":370},"\"a\"",[198,620,380],{"class":312},[198,622,623],{"class":459},"engine",[198,625,345],{"class":308},[198,627,628],{"class":370},"\"openpyxl\"",[198,630,380],{"class":312},[198,632,633],{"class":459},"if_sheet_exists",[198,635,345],{"class":308},[198,637,638],{"class":370},"\"replace\"",[198,640,641],{"class":312},") ",[198,643,316],{"class":308},[198,645,646],{"class":312}," writer:\n",[198,648,649,652,654,656,659,661,663,665,667],{"class":75,"line":248},[198,650,651],{"class":312},"    totals.to_excel(writer, ",[198,653,460],{"class":459},[198,655,345],{"class":308},[198,657,658],{"class":370},"\"Summary\"",[198,660,380],{"class":312},[198,662,470],{"class":459},[198,664,345],{"class":308},[198,666,475],{"class":351},[198,668,355],{"class":312},[198,670,671,674,676,679,681],{"class":75,"line":254},[198,672,673],{"class":312},"    ws ",[198,675,345],{"class":308},[198,677,678],{"class":312}," writer.book[",[198,680,465],{"class":370},[198,682,683],{"class":312},"]\n",[198,685,686,689,691],{"class":75,"line":260},[198,687,688],{"class":312},"    last ",[198,690,345],{"class":308},[198,692,693],{"class":312}," ws.max_row\n",[198,695,696],{"class":75,"line":266},[198,697,698],{"class":312},"    ws.conditional_formatting.add(\n",[198,700,701,704,707,710,713,716,719],{"class":75,"line":272},[198,702,703],{"class":308},"        f",[198,705,706],{"class":370},"\"A2:C",[198,708,584],{"class":709},"sSjpA",[198,711,712],{"class":312},"last",[198,714,715],{"class":709},"}",[198,717,718],{"class":370},"\"",[198,720,721],{"class":312},",\n",[198,723,724,727,730,732,735,738,740,743,745,748,751,753,756,758,761],{"class":75,"line":278},[198,725,726],{"class":312},"        FormulaRule(",[198,728,729],{"class":459},"formula",[198,731,345],{"class":308},[198,733,734],{"class":312},"[",[198,736,737],{"class":370},"\"$C2>1000\"",[198,739,415],{"class":312},[198,741,742],{"class":459},"fill",[198,744,345],{"class":308},[198,746,747],{"class":312},"PatternFill(",[198,749,750],{"class":370},"\"solid\"",[198,752,380],{"class":312},[198,754,755],{"class":459},"fgColor",[198,757,345],{"class":308},[198,759,760],{"class":370},"\"FCE9E9\"",[198,762,763],{"class":312},")),\n",[198,765,766],{"class":75,"line":284},[198,767,768],{"class":312},"    )\n",[198,770,771],{"class":75,"line":290},[198,772,337],{"emptyLinePlaceholder":336},[198,774,776,779,782,784,786,788,790,792],{"class":75,"line":775},17,[198,777,778],{"class":351},"print",[198,780,781],{"class":312},"(pd.read_excel(",[198,783,454],{"class":370},[198,785,380],{"class":312},[198,787,460],{"class":459},[198,789,345],{"class":308},[198,791,658],{"class":370},[198,793,794],{"class":312},"))\n",[10,796,797,798,802],{},"The two are about the same length, and each shows its character. The VBA macro walks the cells one by one and paints fixed colours — natural inside Excel, where the cells ",[799,800,801],"em",{},"are"," the data. The Python version treats the sheet as a table, aggregates it in one call, and adds a conditional formatting rule, so the highlighting follows the data if someone edits an amount. It also ran without Excel, which means it can run on a server at 6 a.m. The VBA runs only when someone opens the workbook in desktop Excel and clicks.",[180,804,806],{"id":805},"how-they-compare","How they compare",[20,808,29,813,29,816,29,819,29,822,29,827,29,832,29,837,29,840,29,843,29,848,29,853,29,855,29,861,29,863,29,869,29,872,29,876,29,878,29,883,29,885,29,891,29,894,29,898,29,900,29,905,29,907,29,912,29,915,29,919,29,921,29,926,29,928,29,933,29,936,29,940,29,942,29,947,29,949,29,954,29,957,29,961,29,963,29,968,29,970,29,975,29,978,29,982,29,984,29,989,29,991,29,996,29,999,29,1003,29,1005,29,1010,29,1012],{"viewBox":809,"role":23,"ariaLabelledBy":810,"xmlns":27,"style":28},"4 0 752 344",[811,812],"vba-matrix-t","vba-matrix-d",[31,814,815],{"id":811},"VBA and Python compared on the points that decide projects",[35,817,818],{"id":812},"VBA runs inside desktop Excel, handles buttons and events natively, and needs macro-enabled files that are blocked by default when downloaded. Python runs without Excel, suits servers and schedules, processes large data quickly with pandas, has testing and version control tooling, and can drive Excel on Windows via xlwings or COM.",[39,820],{"x":41,"y":42,"width":43,"height":821,"fill":45},"344",[39,823],{"x":48,"y":49,"width":824,"height":825,"rx":42,"fill":45,"stroke":826,"style":80},"261.2","40.0","var(--line,#cdd5e6)",[39,828],{"x":829,"y":49,"width":830,"height":825,"rx":42,"fill":128,"stroke":129,"style":831},"281.2","229.4","stroke-width:1.2px",[68,833,73],{"x":834,"y":835,"style":836},"395.9","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[39,838],{"x":839,"y":49,"width":830,"height":825,"rx":42,"fill":128,"stroke":129,"style":831},"510.6",[68,841,141],{"x":842,"y":835,"style":836},"625.3",[39,844],{"x":48,"y":845,"width":824,"height":846,"rx":42,"fill":847,"stroke":826,"style":80},"56.0","34.0","#e7ebef",[68,849,852],{"x":850,"y":71,"style":851},"32.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","Runs without Excel installed",[39,854],{"x":829,"y":845,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,856,858],{"transform":857},"translate(387.9,65.0) scale(0.667)",[61,859],{"d":123,"fill":64,"stroke":124,"style":860},"stroke-width:2.70px;stroke-linecap:round;stroke-linejoin:round",[39,862],{"x":839,"y":845,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,864,866],{"transform":865},"translate(616.3,64.0) scale(0.750)",[61,867],{"d":92,"fill":64,"stroke":93,"style":868},"stroke-width:2.40px;stroke-linecap:round;stroke-linejoin:round",[39,870],{"x":48,"y":871,"width":824,"height":846,"rx":42,"fill":847,"stroke":826,"style":80},"90.0",[68,873,875],{"x":850,"y":874,"style":851},"112.0","Buttons, events, user forms",[39,877],{"x":829,"y":871,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,879,881],{"transform":880},"translate(386.9,98.0) scale(0.750)",[61,882],{"d":92,"fill":64,"stroke":93,"style":868},[39,884],{"x":839,"y":871,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,886,888],{"transform":887},"translate(616.8,98.5) scale(0.708)",[61,889],{"d":113,"fill":64,"stroke":54,"style":890},"stroke-width:2.54px;stroke-linecap:round;stroke-linejoin:round",[39,892],{"x":48,"y":893,"width":824,"height":846,"rx":42,"fill":847,"stroke":826,"style":80},"124.0",[68,895,897],{"x":850,"y":896,"style":851},"146.0","Runs on a server or schedule",[39,899],{"x":829,"y":893,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,901,903],{"transform":902},"translate(387.4,132.5) scale(0.708)",[61,904],{"d":113,"fill":64,"stroke":54,"style":890},[39,906],{"x":839,"y":893,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,908,910],{"transform":909},"translate(616.3,132.0) scale(0.750)",[61,911],{"d":92,"fill":64,"stroke":93,"style":868},[39,913],{"x":48,"y":914,"width":824,"height":846,"rx":42,"fill":847,"stroke":826,"style":80},"158.0",[68,916,918],{"x":850,"y":917,"style":851},"180.0","Fast on 100k+ rows of data",[39,920],{"x":829,"y":914,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,922,924],{"transform":923},"translate(387.4,166.5) scale(0.708)",[61,925],{"d":113,"fill":64,"stroke":54,"style":890},[39,927],{"x":839,"y":914,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,929,931],{"transform":930},"translate(616.3,166.0) scale(0.750)",[61,932],{"d":92,"fill":64,"stroke":93,"style":868},[39,934],{"x":48,"y":935,"width":824,"height":846,"rx":42,"fill":847,"stroke":826,"style":80},"192.0",[68,937,939],{"x":850,"y":938,"style":851},"214.0","Databases, APIs, other files",[39,941],{"x":829,"y":935,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,943,945],{"transform":944},"translate(387.4,200.5) scale(0.708)",[61,946],{"d":113,"fill":64,"stroke":54,"style":890},[39,948],{"x":839,"y":935,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,950,952],{"transform":951},"translate(616.3,200.0) scale(0.750)",[61,953],{"d":92,"fill":64,"stroke":93,"style":868},[39,955],{"x":48,"y":956,"width":824,"height":846,"rx":42,"fill":847,"stroke":826,"style":80},"226.0",[68,958,960],{"x":850,"y":959,"style":851},"248.0","Unit tests and version control",[39,962],{"x":829,"y":956,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,964,966],{"transform":965},"translate(387.4,234.5) scale(0.708)",[61,967],{"d":113,"fill":64,"stroke":54,"style":890},[39,969],{"x":839,"y":956,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,971,973],{"transform":972},"translate(616.3,234.0) scale(0.750)",[61,974],{"d":92,"fill":64,"stroke":93,"style":868},[39,976],{"x":48,"y":977,"width":824,"height":846,"rx":42,"fill":847,"stroke":826,"style":80},"260.0",[68,979,981],{"x":850,"y":980,"style":851},"282.0","Works in Excel for the web",[39,983],{"x":829,"y":977,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,985,987],{"transform":986},"translate(387.9,269.0) scale(0.667)",[61,988],{"d":123,"fill":64,"stroke":124,"style":860},[39,990],{"x":839,"y":977,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,992,994],{"transform":993},"translate(616.8,268.5) scale(0.708)",[61,995],{"d":113,"fill":64,"stroke":54,"style":890},[39,997],{"x":48,"y":998,"width":824,"height":846,"rx":42,"fill":847,"stroke":826,"style":80},"294.0",[68,1000,1002],{"x":850,"y":1001,"style":851},"316.0","Delivered file needs macros enabled",[39,1004],{"x":829,"y":998,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,1006,1008],{"transform":1007},"translate(386.9,302.0) scale(0.750)",[61,1009],{"d":92,"fill":64,"stroke":93,"style":868},[39,1011],{"x":839,"y":998,"width":830,"height":846,"rx":42,"fill":45,"stroke":826,"style":80},[57,1013,1015],{"transform":1014},"translate(617.3,303.0) scale(0.667)",[61,1016],{"d":123,"fill":64,"stroke":124,"style":860},[10,1018,1019],{},"A few rows deserve comment.",[10,1021,1022,1026,1027,1030,1031,1035],{},[1023,1024,1025],"strong",{},"Interaction."," If the requirement is \"when the user changes a cell, recalculate this and colour that\", or \"a button that opens a form\", VBA is the natural tool: it lives in the workbook and receives Excel's events. Python can be ",[799,1028,1029],{},"called"," from a button — see ",[14,1032,1034],{"href":1033},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings\u002F","Run Python from an Excel Button with xlwings RunPython"," — but event handling itself stays in VBA.",[10,1037,1038,1041],{},[1023,1039,1040],{},"Data work."," Joining a CRM export to a price list, cleaning ten thousand addresses, aggregating a year of transactions: pandas does these in a few lines and at compiled speed. The same in VBA means loops, dictionaries and arrays, and it slows down sharply as data grows.",[10,1043,1044,1047,1048,1051,1052,1055],{},[1023,1045,1046],{},"Security and delivery."," Workbooks with macros must be ",[195,1049,1050],{},".xlsm",", and Microsoft blocks macros by default in files that arrive from the internet, so recipients see a security banner or nothing at all. A Python job that generates a plain ",[195,1053,1054],{},".xlsx"," delivers a file with no code in it — nothing to enable, nothing to block.",[10,1057,1058,1061,1062,1066],{},[1023,1059,1060],{},"Maintenance."," VBA lives inside binary workbooks, which makes diffs, code review and automated tests awkward. Python code lives in text files with the whole ecosystem of linters, tests and version control — the practices in ",[14,1063,1065],{"href":1064},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002F","Testing and Packaging Excel Automation Scripts"," apply directly.",[180,1068,1070],{"id":1069},"choosing-and-combining","Choosing, and combining",[20,1072,29,1077,29,1080,29,1083,29,1086,29,1092,29,1099,29,1104,29,1108,29,1111,29,1114,29,1119,29,1126,29,1131,29,1136,29,1141,29,1145,29,1150,29,1152,29,1155,29,1159,29,1162,29,1166,29,1172,29,1175,29,1178,29,1180,29,1183,29,1187,29,1190,29,1193,29,1199,29,1202],{"viewBox":1073,"role":23,"ariaLabelledBy":1074,"xmlns":27,"style":28},"4 0 752 272",[1075,1076],"vba-choose-t","vba-choose-d",[31,1078,1079],{"id":1075},"Choosing between VBA and Python for an Excel task",[35,1081,1082],{"id":1076},"If the task reacts to what a user does inside an open workbook, use VBA. If it processes data or produces files unattended, use Python. If a user should trigger heavy data work from inside Excel, combine them with a button that calls Python.",[39,1084],{"x":41,"y":42,"width":43,"height":1085,"fill":45},"272",[39,1087],{"x":1088,"y":49,"width":1089,"height":1090,"rx":1091,"fill":128,"stroke":129,"style":55},"240.0","280.0","75.5","12",[57,1093,1095],{"transform":1094},"translate(368.0,29.0) scale(1.000)",[61,1096],{"d":1097,"fill":64,"stroke":136,"style":1098},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[68,1100,1103],{"x":1101,"y":1090,"style":1102},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","What does the task do?",[75,1105],{"x1":1101,"y1":1106,"x2":1101,"y2":1107,"stroke":129,"style":55},"91.5","111.5",[75,1109],{"x1":1110,"y1":1107,"x2":842,"y2":1107,"stroke":129,"style":55},"134.7",[75,1112],{"x1":1110,"y1":1107,"x2":1110,"y2":1113,"stroke":129,"style":55},"157.5",[1115,1116],"polygon",{"points":1117,"fill":1118},"134.7,161.5 129.7,152.5 139.7,152.5","#5b5cf0",[39,1120],{"x":1121,"y":1122,"width":1123,"height":1124,"rx":1125,"fill":45,"stroke":826,"style":831},"49.8","121.5","169.8","21.0","10",[68,1127,1130],{"x":1110,"y":1128,"style":1129},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","reacts to the user in Excel",[39,1132],{"x":48,"y":1133,"width":1134,"height":1135,"rx":1091,"fill":53,"stroke":54,"style":55},"163.5","229.3","93.0",[57,1137,1139],{"transform":1138},"translate(122.7,176.5) scale(1.000)",[61,1140],{"d":63,"fill":64,"stroke":65,"style":1098},[68,1142,73],{"x":1110,"y":1143,"style":1144},"223.0","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle",[68,1146,1149],{"x":1110,"y":1147,"style":1148},"242.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","events, forms, buttons",[75,1151],{"x1":1101,"y1":1107,"x2":1101,"y2":1113,"stroke":129,"style":55},[1115,1153],{"points":1154,"fill":1118},"380.0,161.5 375.0,152.5 385.0,152.5",[39,1156],{"x":1157,"y":1122,"width":1158,"height":1124,"rx":1125,"fill":45,"stroke":826,"style":831},"304.0","152.0",[68,1160,1161],{"x":1101,"y":1128,"style":1129},"processes data or files",[39,1163],{"x":1164,"y":1133,"width":1134,"height":1135,"rx":1091,"fill":1165,"stroke":93,"style":55},"265.3","#d9f4f1",[57,1167,1169],{"transform":1168},"translate(368.0,176.5) scale(1.000)",[61,1170],{"d":135,"fill":64,"stroke":1171,"style":1098},"var(--teal-ink,#0b6157)",[68,1173,141],{"x":1101,"y":1143,"style":1174},"font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[68,1176,1177],{"x":1101,"y":1147,"style":1148},"pandas, openpyxl, schedules",[75,1179],{"x1":842,"y1":1107,"x2":842,"y2":1113,"stroke":129,"style":55},[1115,1181],{"points":1182,"fill":1118},"625.3,161.5 620.3,152.5 630.3,152.5",[39,1184],{"x":1185,"y":1122,"width":1186,"height":1124,"rx":1125,"fill":45,"stroke":826,"style":831},"602.9","45.0",[68,1188,1189],{"x":842,"y":1128,"style":1129},"both",[39,1191],{"x":1192,"y":1133,"width":1134,"height":1135,"rx":1091,"fill":128,"stroke":129,"style":55},"510.7",[57,1194,1196],{"transform":1195},"translate(613.3,176.5) scale(1.000)",[61,1197],{"d":1198,"fill":64,"stroke":136,"style":1098},"M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1 M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1",[68,1200,1201],{"x":842,"y":1143,"style":1102},"VBA button → Python",[68,1203,1204],{"x":842,"y":1147,"style":1148},"xlwings RunPython",[10,1206,1207,1208,1212],{},"The combinations are often better than either alone. A workbook keeps a small VBA macro for its buttons while the heavy lifting runs in Python; or an existing VBA-heavy workbook stays as it is while a Python job feeds it cleaned data every morning. When you do need to run an existing macro from Python — for example as one step in a scheduled job — see ",[14,1209,1211],{"href":1210},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Frun-an-excel-macro-from-python-with-win32com\u002F","Run an Excel Macro from Python with win32com",".",[180,1214,1216],{"id":1215},"where-office-scripts-fit","Where Office Scripts fit",[10,1218,1219,1220,1223],{},"Workbooks increasingly live in SharePoint and OneDrive and are opened in the browser, where VBA does not run at all. Excel for the web has its own automation language, ",[1023,1221,1222],{},"Office Scripts",": TypeScript scripts stored with the user's account rather than in the workbook, recordable with an action recorder, and able to run from a button in the workbook or from a Power Automate flow on a schedule. For a team whose files already live in Microsoft 365, they cover a good part of what small VBA macros used to do — formatting a sheet, copying a range, refreshing a table — without macro-enabled files.",[10,1225,1226,1227,1231,1232,1212],{},"They do not replace Python for data work. Office Scripts run with limits on execution time and on how much data a script can move per call, and they have no equivalent of pandas. The practical split in a Microsoft 365 setup is: Office Scripts for small in-workbook actions that users trigger, Python — running as a scheduled job and editing cloud workbooks through Microsoft Graph — for the heavy processing. The Graph side of that is covered in ",[14,1228,1230],{"href":1229},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002F","Automating Excel Online with Microsoft Graph",". Python in Excel is a fourth option again: Python code inside cells, for analysis rather than automation, with the constraints described in ",[14,1233,1235],{"href":1234},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002F","Using Python in Excel",[180,1237,1239],{"id":1238},"migrating-a-vba-macro-to-python","Migrating a VBA macro to Python",[10,1241,1242,1243,1212],{},"Rewriting working VBA is only worth it when the macro has outgrown Excel: it processes more data every month, it needs to run without someone clicking, or several people now maintain it. Migrate in slices rather than all at once. Start with the data processing — the loops that read, filter and aggregate — and replace them with a Python step that writes its results to a sheet the macro reads. Leave the user-facing parts in VBA until there is a reason to move them. Check the result against the old macro on real files before switching over: run both on last month's input and compare the output workbooks cell by cell, as in ",[14,1244,1246],{"href":1245},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fcompare-two-excel-files-for-differences-with-python\u002F","Compare Two Excel Files for Differences with Python",[180,1248,1250],{"id":1249},"common-pitfalls","Common pitfalls",[1252,1253,1254,1261,1271,1280],"ul",{},[1255,1256,1257,1260],"li",{},[1023,1258,1259],{},"Choosing by familiarity alone."," A team fluent in VBA will write data pipelines in VBA that would be a tenth of the length in pandas; a Python team will fight Excel's object model for what a five-line macro does. Match the tool to the task.",[1255,1262,1263,1266,1267,1212],{},[1023,1264,1265],{},"Driving Excel from Python cell by cell."," Through COM each cell access is a cross-process call. If Python must drive Excel, read and write whole ranges at once — see ",[14,1268,1270],{"href":1269},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fspeed-up-xlwings-with-bulk-reads-and-writes\u002F","Speed Up xlwings with Bulk Reads and Writes",[1255,1272,1273,1276,1277,1279],{},[1023,1274,1275],{},"Shipping macros to external recipients."," Blocked macros are the norm now. Deliver plain ",[195,1278,1054],{}," output and keep code on your side.",[1255,1281,1282,1285],{},[1023,1283,1284],{},"Assuming Office Scripts is VBA."," Excel for the web uses Office Scripts (TypeScript), not VBA. Neither VBA nor desktop-style Python automation runs there.",[180,1287,1289],{"id":1288},"conclusion","Conclusion",[10,1291,1292],{},"VBA belongs inside desktop Excel, reacting to users with buttons, events and forms. Python belongs around Excel: processing data with pandas, generating and delivering workbooks without Excel, running on schedules and servers, and living in version-controlled, testable code. Use VBA for interaction, Python for data and delivery, and connect them with a button or a scheduled job when a task needs both.",[180,1294,1296],{"id":1295},"frequently-asked-questions","Frequently asked questions",[10,1298,1299,1302],{},[1023,1300,1301],{},"Is Python replacing VBA in Excel?","\nNo. VBA is still supported in desktop Excel and remains the simplest way to automate the application's user interface from inside a workbook. Python is better for processing data, building reports outside Excel, and running unattended on servers. Many teams use both.",[10,1304,1305,1308],{},[1023,1306,1307],{},"Can Python do everything VBA can?","\nNot from outside Excel. Python libraries such as openpyxl write files without Excel, so they cannot respond to clicks, show dialogs or run when a cell changes. Driving the application with xlwings or COM from Python covers much of VBA's reach on Windows, but event-driven features still belong to VBA.",[10,1310,1311,1314],{},[1023,1312,1313],{},"Why do my VBA macros not run in files downloaded from the internet?","\nMicrosoft blocks macros by default in Office files marked as coming from the internet. Users must unblock the file or it must come from a trusted location. Python scripts that generate plain .xlsx files avoid macros in the delivered workbook altogether.",[10,1316,1317,1320],{},[1023,1318,1319],{},"Which is faster?","\nFor cell-by-cell work inside Excel, VBA is usually faster than Python driving Excel through COM, because each COM call crosses a process boundary. For processing data — joining, aggregating, cleaning — Python with pandas working on the data outside Excel is typically far faster than VBA loops over cells.",[180,1322,1324],{"id":1323},"related","Related",[1252,1326,1327,1333,1340,1347],{},[1255,1328,1329,1330,1332],{},"Up one level: ",[14,1331,17],{"href":16}," — picking tools for Excel work.",[1255,1334,1335,1339],{},[14,1336,1338],{"href":1337},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fxlwings-run-macro-from-python-example\u002F","xlwings: Run a VBA Macro From Python"," — reusing existing macros.",[1255,1341,1342,1346],{},[14,1343,1345],{"href":1344},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fwork-with-macro-enabled-xlsm-files-in-openpyxl\u002F","Work with Macro-Enabled .xlsm Files in openpyxl"," — keeping VBA intact.",[1255,1348,1349,1353],{},[14,1350,1352],{"href":1351},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-power-query-for-cleaning-excel-data\u002F","Python vs Power Query for Cleaning Excel Data"," — the other built-in alternative.",[1355,1356,1357],"style",{},"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 .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":193,"searchDepth":206,"depth":206,"links":1359},[1360,1361,1362,1363,1364,1365,1366,1367,1368],{"id":182,"depth":206,"text":183},{"id":805,"depth":206,"text":806},{"id":1069,"depth":206,"text":1070},{"id":1215,"depth":206,"text":1216},{"id":1238,"depth":206,"text":1239},{"id":1249,"depth":206,"text":1250},{"id":1288,"depth":206,"text":1289},{"id":1295,"depth":206,"text":1296},{"id":1323,"depth":206,"text":1324},"2026-09-23","When to automate Excel with VBA and when with Python — where each runs, what each is good at, security and deployment, speed on real data, and a side-by-side of the same task in both, plus ways to use them together.","md",[1373,1375,1377,1379],{"q":1301,"a":1374},"No. VBA is still supported in desktop Excel and remains the simplest way to automate the application's user interface from inside a workbook. Python is better for processing data, building reports outside Excel, and running unattended on servers. Many teams use both.",{"q":1307,"a":1376},"Not from outside Excel. Python libraries such as openpyxl write files without Excel, so they cannot respond to clicks, show dialogs or run when a cell changes. Driving the application with xlwings or COM from Python covers much of VBA's reach on Windows, but event-driven features still belong to VBA.",{"q":1313,"a":1378},"Microsoft blocks macros by default in Office files marked as coming from the internet. Users must unblock the file or it must come from a trusted location. Python scripts that generate plain .xlsx files avoid macros in the delivered workbook altogether.",{"q":1319,"a":1380},"For cell-by-cell work inside Excel, VBA is usually faster than Python driving Excel through COM, because each COM call crosses a process boundary. For processing data — joining, aggregating, cleaning — Python with pandas working on the data outside Excel is typically far faster than VBA loops over cells.","python vs vba for excel automation",null,{"breadcrumb":1384},[1385,1388,1391],{"name":1386,"item":1387},"Home","\u002F",{"name":1389,"item":1390},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":17,"item":16},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation",{"title":1394,"description":1395},"Python vs VBA for Excel Automation — Which Should You Use?","A practical comparison of Python and VBA for Excel work — in-workbook interaction versus data processing, macro security, deployment, testing, speed — with the same report built in both languages.","python-vs-vba-for-excel-automation","getting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation\u002Findex",[1399,1400],"choosing-libraries","macros-and-vba","how-to","9uFmQLwwE6UqOyA1xeTSiUf0RUxSR8MzgzmyS_CBW9g",[1404,1407],{"title":1352,"path":1405,"stem":1406,"children":-1},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-power-query-for-cleaning-excel-data","getting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-power-query-for-cleaning-excel-data\u002Findex",{"title":1408,"path":1409,"stem":1410,"children":-1},"Translate Common VBA Macros to Python","\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Ftranslate-common-vba-macros-to-python","getting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Ftranslate-common-vba-macros-to-python\u002Findex",[1412,1414],{"path":1413,"title":17},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library",{"path":1415,"title":1389},"\u002Fgetting-started-with-python-excel-automation",[],[1418,1422,1425,1428,1431,1434],{"path":1419,"title":1420,"kind":1421},"\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":1423,"title":1424,"kind":1421},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fopenpyxl-vs-xlsxwriter-vs-pandas-excelwriter","openpyxl vs xlsxwriter vs pandas.ExcelWriter",{"path":1426,"title":1427,"kind":1401},"\u002Fautomating-reporting-workflows\u002Fscheduling-python-excel-scripts-with-cron\u002Fchoose-a-scheduler-for-python-excel-reports","Choose a Scheduler for Python Excel Reports",{"path":1429,"title":1430,"kind":1421},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fgoogle-sheets-vs-excel-files-for-python-automation","Google Sheets vs Excel Files for Python Automation",{"path":1432,"title":1433,"kind":1401},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Flightweight-python-excel-libraries-compared","Lightweight Python Excel Libraries Compared",{"path":1435,"title":1436,"kind":1421},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fopenpyxl-vs-pandas-for-excel-automation","openpyxl vs pandas for Excel Automation",1790972058936]