[{"data":1,"prerenderedAt":840},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-tuples-namedtuples-explained":3},{"id":4,"title":5,"body":6,"description":826,"difficulty":827,"extension":828,"framework":829,"frameworkSlug":44,"meta":830,"navigation":183,"order":84,"path":831,"qaPath":832,"seo":833,"stem":834,"subtopic":835,"topic":836,"topicSlug":837,"updated":838,"__hash__":839},"blog\u002Fblog\u002Fpython-tuples-namedtuples-explained.md","Python Tuples and Named Tuples Explained — Immutability, Packing, and namedtuple",{"type":7,"value":8,"toc":815},"minimark",[9,14,27,31,39,112,123,127,130,223,230,261,265,268,336,340,347,415,430,434,437,505,509,516,639,643,650,781,788,792,811],[10,11,13],"h2",{"id":12},"python-tuples-explained","Python tuples, explained",[15,16,17,18,22,23,26],"p",{},"Tuples look like \"immutable lists\", but that framing misses the point. Tuples model\n",[19,20,21],"strong",{},"fixed records"," — a related group of values with meaning by position — while lists model\n",[19,24,25],{},"homogeneous collections",". This guide covers the distinction, packing\u002Funpacking, the\ndepth of immutability, and named tuples.",[10,28,30],{"id":29},"tuple-vs-list-its-about-meaning","Tuple vs list: it's about meaning",[15,32,33,34,38],{},"The technical difference is mutability, but the ",[35,36,37],"em",{},"idiomatic"," difference is intent:",[40,41,46],"pre",{"className":42,"code":43,"language":44,"meta":45,"style":45},"language-python shiki shiki-themes github-light github-dark","point = (3, 4)              # a record: (x, y) — fixed structure\nscores = [88, 92, 79]      # a collection: any number of similar items\n","python","",[47,48,49,82],"code",{"__ignoreMap":45},[50,51,54,58,62,65,69,72,75,78],"span",{"class":52,"line":53},"line",1,[50,55,57],{"class":56},"sVt8B","point ",[50,59,61],{"class":60},"szBVR","=",[50,63,64],{"class":56}," (",[50,66,68],{"class":67},"sj4cs","3",[50,70,71],{"class":56},", ",[50,73,74],{"class":67},"4",[50,76,77],{"class":56},")              ",[50,79,81],{"class":80},"sJ8bj","# a record: (x, y) — fixed structure\n",[50,83,85,88,90,93,96,98,101,103,106,109],{"class":52,"line":84},2,[50,86,87],{"class":56},"scores ",[50,89,61],{"class":60},[50,91,92],{"class":56}," [",[50,94,95],{"class":67},"88",[50,97,71],{"class":56},[50,99,100],{"class":67},"92",[50,102,71],{"class":56},[50,104,105],{"class":67},"79",[50,107,108],{"class":56},"]      ",[50,110,111],{"class":80},"# a collection: any number of similar items\n",[15,113,114,115,118,119,122],{},"Use a ",[19,116,117],{},"tuple"," when position has meaning and the size is fixed (coordinates, a database\nrow, a function returning multiple values). Use a ",[19,120,121],{},"list"," when you have a sequence of\nsimilar things you might add to or reorder.",[10,124,126],{"id":125},"packing-and-unpacking","Packing and unpacking",[15,128,129],{},"Creating a tuple is \"packing\"; pulling it apart is \"unpacking\". Parentheses are often\noptional:",[40,131,133],{"className":42,"code":132,"language":44,"meta":45,"style":45},"p = 3, 4              # packing — p is (3, 4)\nx, y = p             # unpacking\nx, y = y, x          # swap with no temp variable\n\nfirst, *rest = [1, 2, 3, 4]   # first=1, rest=[2, 3, 4] — star unpacking\n",[47,134,135,152,165,178,185],{"__ignoreMap":45},[50,136,137,140,142,145,147,149],{"class":52,"line":53},[50,138,139],{"class":56},"p ",[50,141,61],{"class":60},[50,143,144],{"class":67}," 3",[50,146,71],{"class":56},[50,148,74],{"class":67},[50,150,151],{"class":80},"              # packing — p is (3, 4)\n",[50,153,154,157,159,162],{"class":52,"line":84},[50,155,156],{"class":56},"x, y ",[50,158,61],{"class":60},[50,160,161],{"class":56}," p             ",[50,163,164],{"class":80},"# unpacking\n",[50,166,168,170,172,175],{"class":52,"line":167},3,[50,169,156],{"class":56},[50,171,61],{"class":60},[50,173,174],{"class":56}," y, x          ",[50,176,177],{"class":80},"# swap with no temp variable\n",[50,179,181],{"class":52,"line":180},4,[50,182,184],{"emptyLinePlaceholder":183},true,"\n",[50,186,188,191,194,197,199,201,204,206,209,211,213,215,217,220],{"class":52,"line":187},5,[50,189,190],{"class":56},"first, ",[50,192,193],{"class":60},"*",[50,195,196],{"class":56},"rest ",[50,198,61],{"class":60},[50,200,92],{"class":56},[50,202,203],{"class":67},"1",[50,205,71],{"class":56},[50,207,208],{"class":67},"2",[50,210,71],{"class":56},[50,212,68],{"class":67},[50,214,71],{"class":56},[50,216,74],{"class":67},[50,218,219],{"class":56},"]   ",[50,221,222],{"class":80},"# first=1, rest=[2, 3, 4] — star unpacking\n",[15,224,225,226,229],{},"The one gotcha: a ",[19,227,228],{},"single-element tuple needs a trailing comma",", because the parentheses\nalone mean grouping:",[40,231,233],{"className":42,"code":232,"language":44,"meta":45,"style":45},"(5)      # int 5\n(5,)     # tuple (5,)\n",[47,234,235,249],{"__ignoreMap":45},[50,236,237,240,243,246],{"class":52,"line":53},[50,238,239],{"class":56},"(",[50,241,242],{"class":67},"5",[50,244,245],{"class":56},")      ",[50,247,248],{"class":80},"# int 5\n",[50,250,251,253,255,258],{"class":52,"line":84},[50,252,239],{"class":56},[50,254,242],{"class":67},[50,256,257],{"class":56},",)     ",[50,259,260],{"class":80},"# tuple (5,)\n",[10,262,264],{"id":263},"tuples-as-return-values","Tuples as return values",[15,266,267],{},"A function \"returning multiple values\" is really returning one tuple, which the caller\nunpacks:",[40,269,271],{"className":42,"code":270,"language":44,"meta":45,"style":45},"def min_max(nums):\n    return min(nums), max(nums)   # packs a tuple\n\nlo, hi = min_max([3, 1, 7])       # unpacks it\n",[47,272,273,285,305,309],{"__ignoreMap":45},[50,274,275,278,282],{"class":52,"line":53},[50,276,277],{"class":60},"def",[50,279,281],{"class":280},"sScJk"," min_max",[50,283,284],{"class":56},"(nums):\n",[50,286,287,290,293,296,299,302],{"class":52,"line":84},[50,288,289],{"class":60},"    return",[50,291,292],{"class":67}," min",[50,294,295],{"class":56},"(nums), ",[50,297,298],{"class":67},"max",[50,300,301],{"class":56},"(nums)   ",[50,303,304],{"class":80},"# packs a tuple\n",[50,306,307],{"class":52,"line":167},[50,308,184],{"emptyLinePlaceholder":183},[50,310,311,314,316,319,321,323,325,327,330,333],{"class":52,"line":180},[50,312,313],{"class":56},"lo, hi ",[50,315,61],{"class":60},[50,317,318],{"class":56}," min_max([",[50,320,68],{"class":67},[50,322,71],{"class":56},[50,324,203],{"class":67},[50,326,71],{"class":56},[50,328,329],{"class":67},"7",[50,331,332],{"class":56},"])       ",[50,334,335],{"class":80},"# unpacks it\n",[10,337,339],{"id":338},"is-immutability-deep","Is immutability deep?",[15,341,342,343,346],{},"No — a tuple's immutability is ",[19,344,345],{},"shallow",". You can't rebind which objects the tuple holds,\nbut if one of those objects is mutable, it can still change:",[40,348,350],{"className":42,"code":349,"language":44,"meta":45,"style":45},"t = (1, [2, 3])\nt[1].append(4)       # OK — the list inside is mutable -> (1, [2, 3, 4])\nt[1] = [9]           # TypeError — can't rebind a tuple slot\n",[47,351,352,375,393],{"__ignoreMap":45},[50,353,354,357,359,361,363,366,368,370,372],{"class":52,"line":53},[50,355,356],{"class":56},"t ",[50,358,61],{"class":60},[50,360,64],{"class":56},[50,362,203],{"class":67},[50,364,365],{"class":56},", [",[50,367,208],{"class":67},[50,369,71],{"class":56},[50,371,68],{"class":67},[50,373,374],{"class":56},"])\n",[50,376,377,380,382,385,387,390],{"class":52,"line":84},[50,378,379],{"class":56},"t[",[50,381,203],{"class":67},[50,383,384],{"class":56},"].append(",[50,386,74],{"class":67},[50,388,389],{"class":56},")       ",[50,391,392],{"class":80},"# OK — the list inside is mutable -> (1, [2, 3, 4])\n",[50,394,395,397,399,402,404,406,409,412],{"class":52,"line":167},[50,396,379],{"class":56},[50,398,203],{"class":67},[50,400,401],{"class":56},"] ",[50,403,61],{"class":60},[50,405,92],{"class":56},[50,407,408],{"class":67},"9",[50,410,411],{"class":56},"]           ",[50,413,414],{"class":80},"# TypeError — can't rebind a tuple slot\n",[15,416,417,418,421,422,425,426,429],{},"A consequence: a tuple is hashable ",[19,419,420],{},"only if all its elements are",". ",[47,423,424],{},"(1, 2)"," is a valid\ndict key; ",[47,427,428],{},"(1, [2])"," is not.",[10,431,433],{"id":432},"why-a-tuple-can-be-a-dict-key","Why a tuple can be a dict key",[15,435,436],{},"Because an all-immutable tuple is hashable and its hash never changes, it can be a\ndictionary key or set element — a list cannot:",[40,438,440],{"className":42,"code":439,"language":44,"meta":45,"style":45},"distances = {(0, 0): 0, (3, 4): 5}    # coordinates as keys — fine\n{[0, 0]: 0}                           # TypeError: unhashable type: 'list'\n",[47,441,442,483],{"__ignoreMap":45},[50,443,444,447,449,452,455,457,459,462,464,467,469,471,473,475,477,480],{"class":52,"line":53},[50,445,446],{"class":56},"distances ",[50,448,61],{"class":60},[50,450,451],{"class":56}," {(",[50,453,454],{"class":67},"0",[50,456,71],{"class":56},[50,458,454],{"class":67},[50,460,461],{"class":56},"): ",[50,463,454],{"class":67},[50,465,466],{"class":56},", (",[50,468,68],{"class":67},[50,470,71],{"class":56},[50,472,74],{"class":67},[50,474,461],{"class":56},[50,476,242],{"class":67},[50,478,479],{"class":56},"}    ",[50,481,482],{"class":80},"# coordinates as keys — fine\n",[50,484,485,488,490,492,494,497,499,502],{"class":52,"line":84},[50,486,487],{"class":56},"{[",[50,489,454],{"class":67},[50,491,71],{"class":56},[50,493,454],{"class":67},[50,495,496],{"class":56},"]: ",[50,498,454],{"class":67},[50,500,501],{"class":56},"}                           ",[50,503,504],{"class":80},"# TypeError: unhashable type: 'list'\n",[10,506,508],{"id":507},"namedtuple-fields-with-names","namedtuple — fields with names",[15,510,511,512,515],{},"Plain tuples force you to remember what index means what. ",[47,513,514],{},"collections.namedtuple"," gives\nthe fields names while staying a tuple (and still immutable, lightweight, and unpackable):",[40,517,519],{"className":42,"code":518,"language":44,"meta":45,"style":45},"from collections import namedtuple\n\nPoint = namedtuple(\"Point\", [\"x\", \"y\"])\np = Point(3, 4)\np.x, p.y          # 3, 4 — readable access\np[0]              # 3    — still indexable like a tuple\nx, y = p          # still unpackable\np._replace(x=10)  # Point(x=10, y=4) — returns a new tuple\n",[47,520,521,535,539,565,583,591,605,618],{"__ignoreMap":45},[50,522,523,526,529,532],{"class":52,"line":53},[50,524,525],{"class":60},"from",[50,527,528],{"class":56}," collections ",[50,530,531],{"class":60},"import",[50,533,534],{"class":56}," namedtuple\n",[50,536,537],{"class":52,"line":84},[50,538,184],{"emptyLinePlaceholder":183},[50,540,541,544,546,549,553,555,558,560,563],{"class":52,"line":167},[50,542,543],{"class":56},"Point ",[50,545,61],{"class":60},[50,547,548],{"class":56}," namedtuple(",[50,550,552],{"class":551},"sZZnC","\"Point\"",[50,554,365],{"class":56},[50,556,557],{"class":551},"\"x\"",[50,559,71],{"class":56},[50,561,562],{"class":551},"\"y\"",[50,564,374],{"class":56},[50,566,567,569,571,574,576,578,580],{"class":52,"line":180},[50,568,139],{"class":56},[50,570,61],{"class":60},[50,572,573],{"class":56}," Point(",[50,575,68],{"class":67},[50,577,71],{"class":56},[50,579,74],{"class":67},[50,581,582],{"class":56},")\n",[50,584,585,588],{"class":52,"line":187},[50,586,587],{"class":56},"p.x, p.y          ",[50,589,590],{"class":80},"# 3, 4 — readable access\n",[50,592,594,597,599,602],{"class":52,"line":593},6,[50,595,596],{"class":56},"p[",[50,598,454],{"class":67},[50,600,601],{"class":56},"]              ",[50,603,604],{"class":80},"# 3    — still indexable like a tuple\n",[50,606,608,610,612,615],{"class":52,"line":607},7,[50,609,156],{"class":56},[50,611,61],{"class":60},[50,613,614],{"class":56}," p          ",[50,616,617],{"class":80},"# still unpackable\n",[50,619,621,624,628,630,633,636],{"class":52,"line":620},8,[50,622,623],{"class":56},"p._replace(",[50,625,627],{"class":626},"s4XuR","x",[50,629,61],{"class":60},[50,631,632],{"class":67},"10",[50,634,635],{"class":56},")  ",[50,637,638],{"class":80},"# Point(x=10, y=4) — returns a new tuple\n",[10,640,642],{"id":641},"typingnamedtuple-the-typed-class-based-form","typing.NamedTuple — the typed, class-based form",[15,644,645,646,649],{},"For type hints and a cleaner class syntax, use ",[47,647,648],{},"typing.NamedTuple",":",[40,651,653],{"className":42,"code":652,"language":44,"meta":45,"style":45},"from typing import NamedTuple\n\nclass Point(NamedTuple):\n    x: int\n    y: int\n    def distance(self) -> float:\n        return (self.x ** 2 + self.y ** 2) ** 0.5\n\nPoint(3, 4).distance()   # 5.0\n",[47,654,655,667,671,687,695,702,719,759,763],{"__ignoreMap":45},[50,656,657,659,662,664],{"class":52,"line":53},[50,658,525],{"class":60},[50,660,661],{"class":56}," typing ",[50,663,531],{"class":60},[50,665,666],{"class":56}," NamedTuple\n",[50,668,669],{"class":52,"line":84},[50,670,184],{"emptyLinePlaceholder":183},[50,672,673,676,679,681,684],{"class":52,"line":167},[50,674,675],{"class":60},"class",[50,677,678],{"class":280}," Point",[50,680,239],{"class":56},[50,682,683],{"class":280},"NamedTuple",[50,685,686],{"class":56},"):\n",[50,688,689,692],{"class":52,"line":180},[50,690,691],{"class":56},"    x: ",[50,693,694],{"class":67},"int\n",[50,696,697,700],{"class":52,"line":187},[50,698,699],{"class":56},"    y: ",[50,701,694],{"class":67},[50,703,704,707,710,713,716],{"class":52,"line":593},[50,705,706],{"class":60},"    def",[50,708,709],{"class":280}," distance",[50,711,712],{"class":56},"(self) -> ",[50,714,715],{"class":67},"float",[50,717,718],{"class":56},":\n",[50,720,721,724,726,729,732,735,738,741,744,747,749,751,754,756],{"class":52,"line":607},[50,722,723],{"class":60},"        return",[50,725,64],{"class":56},[50,727,728],{"class":67},"self",[50,730,731],{"class":56},".x ",[50,733,734],{"class":60},"**",[50,736,737],{"class":67}," 2",[50,739,740],{"class":60}," +",[50,742,743],{"class":67}," self",[50,745,746],{"class":56},".y ",[50,748,734],{"class":60},[50,750,737],{"class":67},[50,752,753],{"class":56},") ",[50,755,734],{"class":60},[50,757,758],{"class":67}," 0.5\n",[50,760,761],{"class":52,"line":620},[50,762,184],{"emptyLinePlaceholder":183},[50,764,766,769,771,773,775,778],{"class":52,"line":765},9,[50,767,768],{"class":56},"Point(",[50,770,68],{"class":67},[50,772,71],{"class":56},[50,774,74],{"class":67},[50,776,777],{"class":56},").distance()   ",[50,779,780],{"class":80},"# 5.0\n",[15,782,783,784,787],{},"When you need mutability or lots of behaviour, reach for a ",[47,785,786],{},"@dataclass"," instead; for a\nsmall immutable record, a named tuple is perfect.",[10,789,791],{"id":790},"recap","Recap",[15,793,794,795,797,798,801,802,804,805,807,808,810],{},"Tuples model ",[19,796,21],{},"; lists model ",[19,799,800],{},"collections"," — that intent matters more than\n\"immutable list\". Pack with commas, unpack with assignment (and remember the trailing comma\nfor one-element tuples). Immutability is ",[19,803,345],{},": a tuple can contain a mutable list,\nand a tuple is hashable (usable as a dict key) only when all its elements are. Reach for\n",[47,806,514],{}," or ",[47,809,648],{}," to name the fields without giving up\ntuple-ness.",[812,813,814],"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 .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);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":45,"searchDepth":84,"depth":84,"links":816},[817,818,819,820,821,822,823,824,825],{"id":12,"depth":84,"text":13},{"id":29,"depth":84,"text":30},{"id":125,"depth":84,"text":126},{"id":263,"depth":84,"text":264},{"id":338,"depth":84,"text":339},{"id":432,"depth":84,"text":433},{"id":507,"depth":84,"text":508},{"id":641,"depth":84,"text":642},{"id":790,"depth":84,"text":791},"When to use a tuple over a list, how packing and unpacking work, whether tuple immutability is deep, and how namedtuple and typing.NamedTuple give fields names.","medium","md","Python",{},"\u002Fblog\u002Fpython-tuples-namedtuples-explained","\u002Fpython\u002Fdata-structures\u002Ftuples",{"title":5,"description":826},"blog\u002Fpython-tuples-namedtuples-explained","Tuples & Named Tuples","Data Structures","data-structures","2026-06-19","9XqUE-_RM8SJV2fgQ34l6_1bcp8NXoD4xo_NYzYWh2U",1782244093313]