[{"data":1,"prerenderedAt":874},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-strings-formatting-explained":3},{"id":4,"title":5,"body":6,"description":860,"difficulty":861,"extension":862,"framework":863,"frameworkSlug":39,"meta":864,"navigation":72,"order":110,"path":865,"qaPath":866,"seo":867,"stem":868,"subtopic":869,"topic":870,"topicSlug":871,"updated":872,"__hash__":873},"blog\u002Fblog\u002Fpython-strings-formatting-explained.md","Python Strings and Formatting Explained — f-strings, str vs bytes, and join",{"type":7,"value":8,"toc":849},"minimark",[9,14,27,31,34,135,150,154,160,275,279,299,371,385,389,392,448,451,455,466,532,555,559,562,665,679,762,766,773,802,806,845],[10,11,13],"h2",{"id":12},"python-strings-explained","Python strings, explained",[15,16,17,18,22,23,26],"p",{},"Strings are everywhere, and interviewers use them to probe whether you understand\nimmutability, text-vs-bytes, and performance. This guide covers the three formatting styles,\nthe ",[19,20,21],"code",{},"str","\u002F",[19,24,25],{},"bytes"," divide, the build-a-string trap, and the format spec mini-language.",[10,28,30],{"id":29},"three-ways-to-format-and-which-to-use","Three ways to format — and which to use",[15,32,33],{},"Python has accumulated three formatting styles:",[35,36,41],"pre",{"className":37,"code":38,"language":39,"meta":40,"style":40},"language-python shiki shiki-themes github-light github-dark","name, score = \"Ada\", 98.5\n\nf\"{name} scored {score}\"             # f-string  (3.6+, preferred)\n\"{} scored {}\".format(name, score)   # str.format\n\"%s scored %.1f\" % (name, score)     # %-formatting (oldest)\n","python","",[19,42,43,67,74,108,120],{"__ignoreMap":40},[44,45,48,52,56,60,63],"span",{"class":46,"line":47},"line",1,[44,49,51],{"class":50},"sVt8B","name, score ",[44,53,55],{"class":54},"szBVR","=",[44,57,59],{"class":58},"sZZnC"," \"Ada\"",[44,61,62],{"class":50},", ",[44,64,66],{"class":65},"sj4cs","98.5\n",[44,68,70],{"class":46,"line":69},2,[44,71,73],{"emptyLinePlaceholder":72},true,"\n",[44,75,77,80,83,86,89,92,95,97,100,102,104],{"class":46,"line":76},3,[44,78,79],{"class":54},"f",[44,81,82],{"class":58},"\"",[44,84,85],{"class":65},"{",[44,87,88],{"class":50},"name",[44,90,91],{"class":65},"}",[44,93,94],{"class":58}," scored ",[44,96,85],{"class":65},[44,98,99],{"class":50},"score",[44,101,91],{"class":65},[44,103,82],{"class":58},[44,105,107],{"class":106},"sJ8bj","             # f-string  (3.6+, preferred)\n",[44,109,111,114,117],{"class":46,"line":110},4,[44,112,113],{"class":58},"\"{} scored {}\"",[44,115,116],{"class":50},".format(name, score)   ",[44,118,119],{"class":106},"# str.format\n",[44,121,123,126,129,132],{"class":46,"line":122},5,[44,124,125],{"class":58},"\"%s scored %.1f\"",[44,127,128],{"class":54}," %",[44,130,131],{"class":50}," (name, score)     ",[44,133,134],{"class":106},"# %-formatting (oldest)\n",[15,136,137,141,142,145,146,149],{},[138,139,140],"strong",{},"Prefer f-strings",": they're the fastest, most readable, and evaluate expressions inline.\n",[19,143,144],{},".format()"," is useful when the template is separate from the data (e.g. loaded from a\nconfig). ",[19,147,148],{},"%","-formatting is legacy but still common in logging.",[10,151,153],{"id":152},"f-strings-can-do-more-than-interpolate","f-strings can do more than interpolate",[15,155,156,157,159],{},"f-strings evaluate any expression and support a debugging ",[19,158,55],{}," shortcut and format specs:",[35,161,163],{"className":37,"code":162,"language":39,"meta":40,"style":40},"x = 42\nf\"{x * 2}\"        # '84'        — arbitrary expressions\nf\"{x=}\"           # 'x=42'      — name and value (great for debugging)\nf\"{x:>6}\"         # '    42'    — right-align in 6 columns\nf\"{3.14159:.2f}\"  # '3.14'      — 2 decimal places\nf\"{1000000:,}\"    # '1,000,000' — thousands separator\n",[19,164,165,175,196,216,236,255],{"__ignoreMap":40},[44,166,167,170,172],{"class":46,"line":47},[44,168,169],{"class":50},"x ",[44,171,55],{"class":54},[44,173,174],{"class":65}," 42\n",[44,176,177,179,181,183,185,188,191,193],{"class":46,"line":69},[44,178,79],{"class":54},[44,180,82],{"class":58},[44,182,85],{"class":65},[44,184,169],{"class":50},[44,186,187],{"class":54},"*",[44,189,190],{"class":65}," 2}",[44,192,82],{"class":58},[44,194,195],{"class":106},"        # '84'        — arbitrary expressions\n",[44,197,198,200,202,204,207,209,211,213],{"class":46,"line":76},[44,199,79],{"class":54},[44,201,82],{"class":58},[44,203,85],{"class":65},[44,205,206],{"class":50},"x",[44,208,55],{"class":54},[44,210,91],{"class":65},[44,212,82],{"class":58},[44,214,215],{"class":106},"           # 'x=42'      — name and value (great for debugging)\n",[44,217,218,220,222,224,226,229,231,233],{"class":46,"line":110},[44,219,79],{"class":54},[44,221,82],{"class":58},[44,223,85],{"class":65},[44,225,206],{"class":50},[44,227,228],{"class":54},":>6",[44,230,91],{"class":65},[44,232,82],{"class":58},[44,234,235],{"class":106},"         # '    42'    — right-align in 6 columns\n",[44,237,238,240,242,245,248,250,252],{"class":46,"line":122},[44,239,79],{"class":54},[44,241,82],{"class":58},[44,243,244],{"class":65},"{3.14159",[44,246,247],{"class":54},":.2f",[44,249,91],{"class":65},[44,251,82],{"class":58},[44,253,254],{"class":106},"  # '3.14'      — 2 decimal places\n",[44,256,258,260,262,265,268,270,272],{"class":46,"line":257},6,[44,259,79],{"class":54},[44,261,82],{"class":58},[44,263,264],{"class":65},"{1000000",[44,266,267],{"class":54},":,",[44,269,91],{"class":65},[44,271,82],{"class":58},[44,273,274],{"class":106},"    # '1,000,000' — thousands separator\n",[10,276,278],{"id":277},"str-vs-bytes","str vs bytes",[15,280,281,282,284,285,288,289,284,291,294,295,298],{},"This is a crucial distinction. ",[19,283,21],{}," is a sequence of ",[138,286,287],{},"Unicode code points"," (text);\n",[19,290,25],{},[138,292,293],{},"raw 8-bit values",". You convert between them with an explicit\n",[138,296,297],{},"encoding",":",[35,300,302],{"className":37,"code":301,"language":39,"meta":40,"style":40},"s = \"café\"\nb = s.encode(\"utf-8\")     # b'caf\\xc3\\xa9'  — str -> bytes\nb.decode(\"utf-8\")         # 'café'          — bytes -> str\n\nlen(s)                    # 4 (characters)\nlen(b)                    # 5 (bytes — é is 2 bytes in UTF-8)\n",[19,303,304,314,333,346,350,361],{"__ignoreMap":40},[44,305,306,309,311],{"class":46,"line":47},[44,307,308],{"class":50},"s ",[44,310,55],{"class":54},[44,312,313],{"class":58}," \"café\"\n",[44,315,316,319,321,324,327,330],{"class":46,"line":69},[44,317,318],{"class":50},"b ",[44,320,55],{"class":54},[44,322,323],{"class":50}," s.encode(",[44,325,326],{"class":58},"\"utf-8\"",[44,328,329],{"class":50},")     ",[44,331,332],{"class":106},"# b'caf\\xc3\\xa9'  — str -> bytes\n",[44,334,335,338,340,343],{"class":46,"line":76},[44,336,337],{"class":50},"b.decode(",[44,339,326],{"class":58},[44,341,342],{"class":50},")         ",[44,344,345],{"class":106},"# 'café'          — bytes -> str\n",[44,347,348],{"class":46,"line":110},[44,349,73],{"emptyLinePlaceholder":72},[44,351,352,355,358],{"class":46,"line":122},[44,353,354],{"class":65},"len",[44,356,357],{"class":50},"(s)                    ",[44,359,360],{"class":106},"# 4 (characters)\n",[44,362,363,365,368],{"class":46,"line":257},[44,364,354],{"class":65},[44,366,367],{"class":50},"(b)                    ",[44,369,370],{"class":106},"# 5 (bytes — é is 2 bytes in UTF-8)\n",[15,372,373,374,377,378,381,382,384],{},"You can't mix them: ",[19,375,376],{},"\"a\" + b\"b\""," raises ",[19,379,380],{},"TypeError",". Files, sockets, and APIs deal in\nbytes; your program logic should deal in ",[19,383,21],{},". Decode on the way in, encode on the way out.",[10,386,388],{"id":387},"strings-are-immutable","Strings are immutable",[15,390,391],{},"You can't change a string in place — every \"modification\" creates a new string:",[35,393,395],{"className":37,"code":394,"language":39,"meta":40,"style":40},"s = \"hello\"\ns[0] = \"H\"          # TypeError — strings are immutable\ns = \"H\" + s[1:]     # 'Hello' — a brand-new string\n",[19,396,397,406,425],{"__ignoreMap":40},[44,398,399,401,403],{"class":46,"line":47},[44,400,308],{"class":50},[44,402,55],{"class":54},[44,404,405],{"class":58}," \"hello\"\n",[44,407,408,411,414,417,419,422],{"class":46,"line":69},[44,409,410],{"class":50},"s[",[44,412,413],{"class":65},"0",[44,415,416],{"class":50},"] ",[44,418,55],{"class":54},[44,420,421],{"class":58}," \"H\"",[44,423,424],{"class":106},"          # TypeError — strings are immutable\n",[44,426,427,429,431,433,436,439,442,445],{"class":46,"line":76},[44,428,308],{"class":50},[44,430,55],{"class":54},[44,432,421],{"class":58},[44,434,435],{"class":54}," +",[44,437,438],{"class":50}," s[",[44,440,441],{"class":65},"1",[44,443,444],{"class":50},":]     ",[44,446,447],{"class":106},"# 'Hello' — a brand-new string\n",[15,449,450],{},"Immutability is why strings are hashable (usable as dict keys) and why interning is safe.",[10,452,454],{"id":453},"why-join-beats-in-a-loop","Why join beats += in a loop",[15,456,457,458,461,462,465],{},"Because strings are immutable, ",[19,459,460],{},"+="," in a loop creates a new string every iteration —\nO(n²) total work. ",[19,463,464],{},"str.join"," does it in one pass:",[35,467,469],{"className":37,"code":468,"language":39,"meta":40,"style":40},"# Slow: builds and throws away a string each iteration\nresult = \"\"\nfor word in words:\n    result += word\n\n# Fast and idiomatic: O(n)\nresult = \"\".join(words)\n",[19,470,471,476,486,500,510,514,519],{"__ignoreMap":40},[44,472,473],{"class":46,"line":47},[44,474,475],{"class":106},"# Slow: builds and throws away a string each iteration\n",[44,477,478,481,483],{"class":46,"line":69},[44,479,480],{"class":50},"result ",[44,482,55],{"class":54},[44,484,485],{"class":58}," \"\"\n",[44,487,488,491,494,497],{"class":46,"line":76},[44,489,490],{"class":54},"for",[44,492,493],{"class":50}," word ",[44,495,496],{"class":54},"in",[44,498,499],{"class":50}," words:\n",[44,501,502,505,507],{"class":46,"line":110},[44,503,504],{"class":50},"    result ",[44,506,460],{"class":54},[44,508,509],{"class":50}," word\n",[44,511,512],{"class":46,"line":122},[44,513,73],{"emptyLinePlaceholder":72},[44,515,516],{"class":46,"line":257},[44,517,518],{"class":106},"# Fast and idiomatic: O(n)\n",[44,520,522,524,526,529],{"class":46,"line":521},7,[44,523,480],{"class":50},[44,525,55],{"class":54},[44,527,528],{"class":58}," \"\"",[44,530,531],{"class":50},".join(words)\n",[15,533,534,537,538,542,543,546,547,550,551,554],{},[19,535,536],{},"join"," is a method ",[539,540,541],"em",{},"on the separator",": ",[19,544,545],{},"\", \".join([\"a\", \"b\", \"c\"])"," → ",[19,548,549],{},"'a, b, c'",". The\nitems must all be strings — ",[19,552,553],{},"map(str, ...)"," first if they aren't.",[10,556,558],{"id":557},"common-methods-and-the-format-spec","Common methods and the format spec",[15,560,561],{},"The everyday string toolkit:",[35,563,565],{"className":37,"code":564,"language":39,"meta":40,"style":40},"\"  hi  \".strip()            # 'hi'        — also lstrip\u002Frstrip\n\"a,b,c\".split(\",\")         # ['a', 'b', 'c']\n\"Hello\".lower()            # 'hello'     — also upper, title\n\"file.txt\".endswith(\".txt\")# True        — also startswith\n\"abc\".replace(\"a\", \"x\")    # 'xbc'\n\"name\".center(10, \"-\")     # '---name---'\n",[19,566,567,578,594,605,622,644],{"__ignoreMap":40},[44,568,569,572,575],{"class":46,"line":47},[44,570,571],{"class":58},"\"  hi  \"",[44,573,574],{"class":50},".strip()            ",[44,576,577],{"class":106},"# 'hi'        — also lstrip\u002Frstrip\n",[44,579,580,583,586,589,591],{"class":46,"line":69},[44,581,582],{"class":58},"\"a,b,c\"",[44,584,585],{"class":50},".split(",[44,587,588],{"class":58},"\",\"",[44,590,342],{"class":50},[44,592,593],{"class":106},"# ['a', 'b', 'c']\n",[44,595,596,599,602],{"class":46,"line":76},[44,597,598],{"class":58},"\"Hello\"",[44,600,601],{"class":50},".lower()            ",[44,603,604],{"class":106},"# 'hello'     — also upper, title\n",[44,606,607,610,613,616,619],{"class":46,"line":110},[44,608,609],{"class":58},"\"file.txt\"",[44,611,612],{"class":50},".endswith(",[44,614,615],{"class":58},"\".txt\"",[44,617,618],{"class":50},")",[44,620,621],{"class":106},"# True        — also startswith\n",[44,623,624,627,630,633,635,638,641],{"class":46,"line":122},[44,625,626],{"class":58},"\"abc\"",[44,628,629],{"class":50},".replace(",[44,631,632],{"class":58},"\"a\"",[44,634,62],{"class":50},[44,636,637],{"class":58},"\"x\"",[44,639,640],{"class":50},")    ",[44,642,643],{"class":106},"# 'xbc'\n",[44,645,646,649,652,655,657,660,662],{"class":46,"line":257},[44,647,648],{"class":58},"\"name\"",[44,650,651],{"class":50},".center(",[44,653,654],{"class":65},"10",[44,656,62],{"class":50},[44,658,659],{"class":58},"\"-\"",[44,661,329],{"class":50},[44,663,664],{"class":106},"# '---name---'\n",[15,666,667,668,671,672,674,675,678],{},"The ",[138,669,670],{},"format spec mini-language"," (after the ",[19,673,298],{}," in f-strings and ",[19,676,677],{},".format",") controls\nalignment, padding, precision, and type:",[35,680,682],{"className":37,"code":681,"language":39,"meta":40,"style":40},"f\"{42:08.2f}\"     # '00042.00'  — zero-padded, width 8, 2 decimals\nf\"{255:#x}\"       # '0xff'      — hex with prefix\nf\"{0.25:.1%}\"     # '25.0%'     — percentage\nf\"{'hi':^10}\"     # '    hi    '— centered\n",[19,683,684,703,722,741],{"__ignoreMap":40},[44,685,686,688,690,693,696,698,700],{"class":46,"line":47},[44,687,79],{"class":54},[44,689,82],{"class":58},[44,691,692],{"class":65},"{42",[44,694,695],{"class":54},":08.2f",[44,697,91],{"class":65},[44,699,82],{"class":58},[44,701,702],{"class":106},"     # '00042.00'  — zero-padded, width 8, 2 decimals\n",[44,704,705,707,709,712,715,717,719],{"class":46,"line":69},[44,706,79],{"class":54},[44,708,82],{"class":58},[44,710,711],{"class":65},"{255",[44,713,714],{"class":54},":#x",[44,716,91],{"class":65},[44,718,82],{"class":58},[44,720,721],{"class":106},"       # '0xff'      — hex with prefix\n",[44,723,724,726,728,731,734,736,738],{"class":46,"line":76},[44,725,79],{"class":54},[44,727,82],{"class":58},[44,729,730],{"class":65},"{0.25",[44,732,733],{"class":54},":.1%",[44,735,91],{"class":65},[44,737,82],{"class":58},[44,739,740],{"class":106},"     # '25.0%'     — percentage\n",[44,742,743,745,747,749,752,755,757,759],{"class":46,"line":110},[44,744,79],{"class":54},[44,746,82],{"class":58},[44,748,85],{"class":65},[44,750,751],{"class":58},"'hi'",[44,753,754],{"class":54},":^10",[44,756,91],{"class":65},[44,758,82],{"class":58},[44,760,761],{"class":106},"     # '    hi    '— centered\n",[10,763,765],{"id":764},"raw-strings","Raw strings",[15,767,768,769,772],{},"A raw string (",[19,770,771],{},"r\"...\"",") disables backslash escapes — essential for regex patterns and\nWindows paths:",[35,774,776],{"className":37,"code":775,"language":39,"meta":40,"style":40},"r\"\\d+\\n\"          # literally backslash-d-plus-backslash-n\n\"\\d+\\n\"           # \\d stays literal, but \\n becomes a newline (and warns)\n",[19,777,778,789],{"__ignoreMap":40},[44,779,780,783,786],{"class":46,"line":47},[44,781,782],{"class":54},"r",[44,784,785],{"class":58},"\"\\d+\\n\"",[44,787,788],{"class":106},"          # literally backslash-d-plus-backslash-n\n",[44,790,791,794,797,799],{"class":46,"line":69},[44,792,793],{"class":58},"\"\\d+",[44,795,796],{"class":65},"\\n",[44,798,82],{"class":58},[44,800,801],{"class":106},"           # \\d stays literal, but \\n becomes a newline (and warns)\n",[10,803,805],{"id":804},"recap","Recap",[15,807,808,809,812,813,816,817,819,820,822,823,826,827,830,831,834,835,838,839,841,842,844],{},"Use ",[138,810,811],{},"f-strings"," for almost all formatting — they're fast, readable, and support inline\nexpressions, the ",[19,814,815],{},"{x=}"," debug form, and the format spec mini-language. Keep ",[19,818,21],{},"\n(Unicode text) and ",[19,821,25],{}," (raw octets) separate, converting with explicit ",[19,824,825],{},".encode()","\n\u002F",[19,828,829],{},".decode()",". Strings are ",[138,832,833],{},"immutable",", so build them with ",[19,836,837],{},"\"\".join(parts)"," rather than\n",[19,840,460],{}," in a loop to avoid O(n²) behaviour. Reach for raw strings (",[19,843,771],{},") whenever\nbackslashes should be literal.",[846,847,848],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .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);}",{"title":40,"searchDepth":69,"depth":69,"links":850},[851,852,853,854,855,856,857,858,859],{"id":12,"depth":69,"text":13},{"id":29,"depth":69,"text":30},{"id":152,"depth":69,"text":153},{"id":277,"depth":69,"text":278},{"id":387,"depth":69,"text":388},{"id":453,"depth":69,"text":454},{"id":557,"depth":69,"text":558},{"id":764,"depth":69,"text":765},{"id":804,"depth":69,"text":805},"Python string formatting compared (f-strings, .format, %), the difference between str and bytes, why join beats += in a loop, and the format spec mini-language.","medium","md","Python",{},"\u002Fblog\u002Fpython-strings-formatting-explained","\u002Fpython\u002Ffundamentals\u002Fstrings-formatting",{"title":5,"description":860},"blog\u002Fpython-strings-formatting-explained","Strings & String Formatting","Fundamentals","fundamentals","2026-06-19","NXaSov_Ub3uc8JLJTqf_OBsabSHPtRhZuz85KfpHhpE",1782244093926]