[{"data":1,"prerenderedAt":903},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-dictionaries-explained":3},{"id":4,"title":5,"body":6,"description":889,"difficulty":890,"extension":891,"framework":892,"frameworkSlug":48,"meta":893,"navigation":399,"order":56,"path":894,"qaPath":895,"seo":896,"stem":897,"subtopic":898,"topic":899,"topicSlug":900,"updated":901,"__hash__":902},"blog\u002Fblog\u002Fpython-dictionaries-explained.md","Python Dictionaries Explained — Ordering, Lookups, and Merging",{"type":7,"value":8,"toc":877},"minimark",[9,14,23,27,43,122,129,133,144,195,206,210,221,278,293,300,319,461,480,484,507,609,621,625,646,736,743,747,750,814,818,873],[10,11,13],"h2",{"id":12},"python-dictionaries-explained","Python dictionaries, explained",[15,16,17,18,22],"p",{},"The ",[19,20,21],"code",{},"dict"," is the workhorse of Python — it backs objects' attributes, keyword arguments,\nJSON, and countless lookups. It's also a reliable interview topic because the questions\nprobe real understanding: why lookups are O(1), why keys must be hashable, and what changed\nabout ordering in Python 3.7. This guide walks through the behaviour that matters.",[10,24,26],{"id":25},"o1-lookups-via-hashing","O(1) lookups via hashing",[15,28,29,30,34,35,38,39,42],{},"A dict is a ",[31,32,33],"strong",{},"hash table",": it computes ",[19,36,37],{},"hash(key)"," to decide which bucket a value goes in,\nso lookups, inserts, and deletes are ",[31,40,41],{},"average O(1)"," regardless of size. That's why a dict\ncrushes a list for \"does this key exist?\" — a list is O(n).",[44,45,50],"pre",{"className":46,"code":47,"language":48,"meta":49,"style":49},"language-python shiki shiki-themes github-light github-dark","prices = {\"apple\": 30, \"banana\": 10}\nprices[\"apple\"]          # O(1) — hash to the bucket, no scanning\n\"banana\" in prices       # O(1) membership test\n","python","",[19,51,52,93,108],{"__ignoreMap":49},[53,54,57,61,65,68,72,75,79,82,85,87,90],"span",{"class":55,"line":56},"line",1,[53,58,60],{"class":59},"sVt8B","prices ",[53,62,64],{"class":63},"szBVR","=",[53,66,67],{"class":59}," {",[53,69,71],{"class":70},"sZZnC","\"apple\"",[53,73,74],{"class":59},": ",[53,76,78],{"class":77},"sj4cs","30",[53,80,81],{"class":59},", ",[53,83,84],{"class":70},"\"banana\"",[53,86,74],{"class":59},[53,88,89],{"class":77},"10",[53,91,92],{"class":59},"}\n",[53,94,96,99,101,104],{"class":55,"line":95},2,[53,97,98],{"class":59},"prices[",[53,100,71],{"class":70},[53,102,103],{"class":59},"]          ",[53,105,107],{"class":106},"sJ8bj","# O(1) — hash to the bucket, no scanning\n",[53,109,111,113,116,119],{"class":55,"line":110},3,[53,112,84],{"class":70},[53,114,115],{"class":63}," in",[53,117,118],{"class":59}," prices       ",[53,120,121],{"class":106},"# O(1) membership test\n",[15,123,124,125,128],{},"The cost is memory (buckets and spare capacity) and that keys must be ",[31,126,127],{},"hashable"," — the\nmechanism that makes O(1) possible is the same one that constrains what can be a key.",[10,130,132],{"id":131},"keys-must-be-hashable","Keys must be hashable",[15,134,135,136,139,140,143],{},"A key's hash must stay constant for its lifetime, so keys must be ",[31,137,138],{},"immutable\u002Fhashable",":\nstrings, numbers, tuples, frozensets — but ",[31,141,142],{},"not"," lists, dicts, or sets.",[44,145,147],{"className":46,"code":146,"language":48,"meta":49,"style":49},"{(1, 2): \"point\"}        # tuple key — fine\n{[1, 2]: \"point\"}        # TypeError: unhashable type: 'list'\n",[19,148,149,174],{"__ignoreMap":49},[53,150,151,154,157,159,162,165,168,171],{"class":55,"line":56},[53,152,153],{"class":59},"{(",[53,155,156],{"class":77},"1",[53,158,81],{"class":59},[53,160,161],{"class":77},"2",[53,163,164],{"class":59},"): ",[53,166,167],{"class":70},"\"point\"",[53,169,170],{"class":59},"}        ",[53,172,173],{"class":106},"# tuple key — fine\n",[53,175,176,179,181,183,185,188,190,192],{"class":55,"line":95},[53,177,178],{"class":59},"{[",[53,180,156],{"class":77},[53,182,81],{"class":59},[53,184,161],{"class":77},[53,186,187],{"class":59},"]: ",[53,189,167],{"class":70},[53,191,170],{"class":59},[53,193,194],{"class":106},"# TypeError: unhashable type: 'list'\n",[15,196,197,198,201,202,205],{},"If a mutable key could change after insertion, its hash would change and the value would be\nunfindable in its original bucket. Use a ",[31,199,200],{},"tuple"," instead of a list, a ",[31,203,204],{},"frozenset","\ninstead of a set.",[10,207,209],{"id":208},"insertion-ordering-since-37","Insertion ordering (since 3.7)",[15,211,212,213,216,217,220],{},"As of ",[31,214,215],{},"Python 3.7",", dicts ",[31,218,219],{},"preserve insertion order"," as a language guarantee (it was a\nCPython implementation detail in 3.6). Iterating a dict yields keys in the order they were\nadded.",[44,222,224],{"className":46,"code":223,"language":48,"meta":49,"style":49},"d = {}\nd[\"z\"] = 1\nd[\"a\"] = 2\nlist(d)          # ['z', 'a'] — insertion order, not sorted\n",[19,225,226,236,252,266],{"__ignoreMap":49},[53,227,228,231,233],{"class":55,"line":56},[53,229,230],{"class":59},"d ",[53,232,64],{"class":63},[53,234,235],{"class":59}," {}\n",[53,237,238,241,244,247,249],{"class":55,"line":95},[53,239,240],{"class":59},"d[",[53,242,243],{"class":70},"\"z\"",[53,245,246],{"class":59},"] ",[53,248,64],{"class":63},[53,250,251],{"class":77}," 1\n",[53,253,254,256,259,261,263],{"class":55,"line":110},[53,255,240],{"class":59},[53,257,258],{"class":70},"\"a\"",[53,260,246],{"class":59},[53,262,64],{"class":63},[53,264,265],{"class":77}," 2\n",[53,267,269,272,275],{"class":55,"line":268},4,[53,270,271],{"class":77},"list",[53,273,274],{"class":59},"(d)          ",[53,276,277],{"class":106},"# ['z', 'a'] — insertion order, not sorted\n",[15,279,280,281,284,285,288,289,292],{},"This is why ",[19,282,283],{},"collections.OrderedDict"," is rarely needed now — though it still has uses\n(order-sensitive equality and ",[19,286,287],{},"move_to_end","). To sort, do it explicitly:\n",[19,290,291],{},"dict(sorted(d.items()))",".",[10,294,296,297,299],{"id":295},"get-vs-and-setdefault","get vs ",[53,298],{}," and setdefault",[15,301,302,303,306,307,310,311,314,315,318],{},"Indexing a missing key raises ",[19,304,305],{},"KeyError",". ",[19,308,309],{},"dict.get(key, default)"," returns a default\ninstead, and ",[19,312,313],{},"setdefault(key, default)"," returns the existing value ",[31,316,317],{},"or inserts and returns\nthe default"," — handy for accumulating.",[44,320,322],{"className":46,"code":321,"language":48,"meta":49,"style":49},"counts = {}\nfor word in [\"a\", \"b\", \"a\"]:\n    counts[word] = counts.get(word, 0) + 1     # no KeyError on first sight\ncounts            # {'a': 2, 'b': 1}\n\ngroups = {}\nfor name in [\"ann\", \"amy\", \"bob\"]:\n    groups.setdefault(name[0], []).append(name)  # insert [] if missing, then append\ngroups            # {'a': ['ann', 'amy'], 'b': ['bob']}\n",[19,323,324,333,361,386,394,401,411,438,452],{"__ignoreMap":49},[53,325,326,329,331],{"class":55,"line":56},[53,327,328],{"class":59},"counts ",[53,330,64],{"class":63},[53,332,235],{"class":59},[53,334,335,338,341,344,347,349,351,354,356,358],{"class":55,"line":95},[53,336,337],{"class":63},"for",[53,339,340],{"class":59}," word ",[53,342,343],{"class":63},"in",[53,345,346],{"class":59}," [",[53,348,258],{"class":70},[53,350,81],{"class":59},[53,352,353],{"class":70},"\"b\"",[53,355,81],{"class":59},[53,357,258],{"class":70},[53,359,360],{"class":59},"]:\n",[53,362,363,366,368,371,374,377,380,383],{"class":55,"line":110},[53,364,365],{"class":59},"    counts[word] ",[53,367,64],{"class":63},[53,369,370],{"class":59}," counts.get(word, ",[53,372,373],{"class":77},"0",[53,375,376],{"class":59},") ",[53,378,379],{"class":63},"+",[53,381,382],{"class":77}," 1",[53,384,385],{"class":106},"     # no KeyError on first sight\n",[53,387,388,391],{"class":55,"line":268},[53,389,390],{"class":59},"counts            ",[53,392,393],{"class":106},"# {'a': 2, 'b': 1}\n",[53,395,397],{"class":55,"line":396},5,[53,398,400],{"emptyLinePlaceholder":399},true,"\n",[53,402,404,407,409],{"class":55,"line":403},6,[53,405,406],{"class":59},"groups ",[53,408,64],{"class":63},[53,410,235],{"class":59},[53,412,414,416,419,421,423,426,428,431,433,436],{"class":55,"line":413},7,[53,415,337],{"class":63},[53,417,418],{"class":59}," name ",[53,420,343],{"class":63},[53,422,346],{"class":59},[53,424,425],{"class":70},"\"ann\"",[53,427,81],{"class":59},[53,429,430],{"class":70},"\"amy\"",[53,432,81],{"class":59},[53,434,435],{"class":70},"\"bob\"",[53,437,360],{"class":59},[53,439,441,444,446,449],{"class":55,"line":440},8,[53,442,443],{"class":59},"    groups.setdefault(name[",[53,445,373],{"class":77},[53,447,448],{"class":59},"], []).append(name)  ",[53,450,451],{"class":106},"# insert [] if missing, then append\n",[53,453,455,458],{"class":55,"line":454},9,[53,456,457],{"class":59},"groups            ",[53,459,460],{"class":106},"# {'a': ['ann', 'amy'], 'b': ['bob']}\n",[15,462,463,464,467,468,471,472,475,476,479],{},"For counting and grouping, ",[19,465,466],{},"collections.Counter"," and ",[19,469,470],{},"collections.defaultdict"," are cleaner\nstill — but ",[19,473,474],{},"get","\u002F",[19,477,478],{},"setdefault"," are the built-in tools to know.",[10,481,483],{"id":482},"merging-dictionaries","Merging dictionaries",[15,485,486,487,490,491,494,495,498,499,502,503,506],{},"Since ",[31,488,489],{},"Python 3.9"," the ",[19,492,493],{},"|"," operator merges dicts; ",[19,496,497],{},"|="," updates in place. Before that,\n",[19,500,501],{},"{**a, **b}"," unpacking does the same. In all of them, the ",[31,504,505],{},"right-hand dict wins"," on\nconflicting keys.",[44,508,510],{"className":46,"code":509,"language":48,"meta":49,"style":49},"a = {\"x\": 1, \"y\": 2}\nb = {\"y\": 9, \"z\": 3}\n\na | b            # {'x': 1, 'y': 9, 'z': 3}  — b's y wins\n{**a, **b}       # same result (works pre-3.9)\na.update(b)      # mutates a in place\n",[19,511,512,539,566,570,582,601],{"__ignoreMap":49},[53,513,514,517,519,521,524,526,528,530,533,535,537],{"class":55,"line":56},[53,515,516],{"class":59},"a ",[53,518,64],{"class":63},[53,520,67],{"class":59},[53,522,523],{"class":70},"\"x\"",[53,525,74],{"class":59},[53,527,156],{"class":77},[53,529,81],{"class":59},[53,531,532],{"class":70},"\"y\"",[53,534,74],{"class":59},[53,536,161],{"class":77},[53,538,92],{"class":59},[53,540,541,544,546,548,550,552,555,557,559,561,564],{"class":55,"line":95},[53,542,543],{"class":59},"b ",[53,545,64],{"class":63},[53,547,67],{"class":59},[53,549,532],{"class":70},[53,551,74],{"class":59},[53,553,554],{"class":77},"9",[53,556,81],{"class":59},[53,558,243],{"class":70},[53,560,74],{"class":59},[53,562,563],{"class":77},"3",[53,565,92],{"class":59},[53,567,568],{"class":55,"line":110},[53,569,400],{"emptyLinePlaceholder":399},[53,571,572,574,576,579],{"class":55,"line":268},[53,573,516],{"class":59},[53,575,493],{"class":63},[53,577,578],{"class":59}," b            ",[53,580,581],{"class":106},"# {'x': 1, 'y': 9, 'z': 3}  — b's y wins\n",[53,583,584,587,590,593,595,598],{"class":55,"line":396},[53,585,586],{"class":59},"{",[53,588,589],{"class":63},"**",[53,591,592],{"class":59},"a, ",[53,594,589],{"class":63},[53,596,597],{"class":59},"b}       ",[53,599,600],{"class":106},"# same result (works pre-3.9)\n",[53,602,603,606],{"class":55,"line":403},[53,604,605],{"class":59},"a.update(b)      ",[53,607,608],{"class":106},"# mutates a in place\n",[15,610,611,612,614,615,475,618,620],{},"Pick ",[19,613,493],{}," for a new merged dict, ",[19,616,617],{},"update",[19,619,497],{}," to modify one in place.",[10,622,624],{"id":623},"views-keys-values-items","Views: keys, values, items",[15,626,627,81,630,633,634,637,638,641,642,645],{},[19,628,629],{},".keys()",[19,631,632],{},".values()",", and ",[19,635,636],{},".items()"," return ",[31,639,640],{},"dynamic views",", not lists — they reflect\nlater changes to the dict and avoid copying. Wrap in ",[19,643,644],{},"list(...)"," only if you need a\nsnapshot.",[44,647,649],{"className":46,"code":648,"language":48,"meta":49,"style":49},"d = {\"a\": 1, \"b\": 2}\nkeys = d.keys()\nd[\"c\"] = 3\nlist(keys)       # ['a', 'b', 'c'] — the view updated live\n\nfor k, v in d.items():   # idiomatic iteration\n    print(k, v)\n",[19,650,651,675,685,699,709,713,728],{"__ignoreMap":49},[53,652,653,655,657,659,661,663,665,667,669,671,673],{"class":55,"line":56},[53,654,230],{"class":59},[53,656,64],{"class":63},[53,658,67],{"class":59},[53,660,258],{"class":70},[53,662,74],{"class":59},[53,664,156],{"class":77},[53,666,81],{"class":59},[53,668,353],{"class":70},[53,670,74],{"class":59},[53,672,161],{"class":77},[53,674,92],{"class":59},[53,676,677,680,682],{"class":55,"line":95},[53,678,679],{"class":59},"keys ",[53,681,64],{"class":63},[53,683,684],{"class":59}," d.keys()\n",[53,686,687,689,692,694,696],{"class":55,"line":110},[53,688,240],{"class":59},[53,690,691],{"class":70},"\"c\"",[53,693,246],{"class":59},[53,695,64],{"class":63},[53,697,698],{"class":77}," 3\n",[53,700,701,703,706],{"class":55,"line":268},[53,702,271],{"class":77},[53,704,705],{"class":59},"(keys)       ",[53,707,708],{"class":106},"# ['a', 'b', 'c'] — the view updated live\n",[53,710,711],{"class":55,"line":396},[53,712,400],{"emptyLinePlaceholder":399},[53,714,715,717,720,722,725],{"class":55,"line":403},[53,716,337],{"class":63},[53,718,719],{"class":59}," k, v ",[53,721,343],{"class":63},[53,723,724],{"class":59}," d.items():   ",[53,726,727],{"class":106},"# idiomatic iteration\n",[53,729,730,733],{"class":55,"line":413},[53,731,732],{"class":77},"    print",[53,734,735],{"class":59},"(k, v)\n",[15,737,738,739,742],{},"Key views even support set operations (",[19,740,741],{},"d1.keys() & d2.keys()"," for common keys), which is a\nneat, lesser-known trick.",[10,744,746],{"id":745},"dict-comprehensions","Dict comprehensions",[15,748,749],{},"Build a dict from an iterable in one expression — readable and fast.",[44,751,753],{"className":46,"code":752,"language":48,"meta":49,"style":49},"squares = {n: n * n for n in range(5)}        # {0:0, 1:1, 2:4, 3:9, 4:16}\ninverted = {v: k for k, v in d.items()}       # swap keys and values\n",[19,754,755,792],{"__ignoreMap":49},[53,756,757,760,762,765,768,771,773,775,777,780,783,786,789],{"class":55,"line":56},[53,758,759],{"class":59},"squares ",[53,761,64],{"class":63},[53,763,764],{"class":59}," {n: n ",[53,766,767],{"class":63},"*",[53,769,770],{"class":59}," n ",[53,772,337],{"class":63},[53,774,770],{"class":59},[53,776,343],{"class":63},[53,778,779],{"class":77}," range",[53,781,782],{"class":59},"(",[53,784,785],{"class":77},"5",[53,787,788],{"class":59},")}        ",[53,790,791],{"class":106},"# {0:0, 1:1, 2:4, 3:9, 4:16}\n",[53,793,794,797,799,802,804,806,808,811],{"class":55,"line":95},[53,795,796],{"class":59},"inverted ",[53,798,64],{"class":63},[53,800,801],{"class":59}," {v: k ",[53,803,337],{"class":63},[53,805,719],{"class":59},[53,807,343],{"class":63},[53,809,810],{"class":59}," d.items()}       ",[53,812,813],{"class":106},"# swap keys and values\n",[10,815,817],{"id":816},"recap","Recap",[15,819,29,820,822,823,825,826,829,830,833,834,837,838,475,840,842,843,845,846,848,849,851,852,855,856,475,859,475,862,865,866,475,869,872],{},[31,821,33],{}," giving ",[31,824,41],{}," lookups, which is why keys must be\n",[31,827,828],{},"hashable\u002Fimmutable"," (tuples, not lists). Since ",[31,831,832],{},"3.7"," dicts ",[31,835,836],{},"preserve insertion\norder","; use ",[19,839,474],{},[19,841,478],{}," to handle missing keys without ",[19,844,305],{},", the ",[19,847,493],{}," operator\n(or ",[19,850,501],{},") to merge with right-hand precedence, and the live ",[31,853,854],{},"views"," from\n",[19,857,858],{},"keys()",[19,860,861],{},"values()",[19,863,864],{},"items()"," for iteration. Reach for ",[19,867,868],{},"Counter",[19,870,871],{},"defaultdict"," when\ncounting or grouping. Understand the hash table underneath and every dict behaviour follows.",[874,875,876],"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":49,"searchDepth":95,"depth":95,"links":878},[879,880,881,882,883,885,886,887,888],{"id":12,"depth":95,"text":13},{"id":25,"depth":95,"text":26},{"id":131,"depth":95,"text":132},{"id":208,"depth":95,"text":209},{"id":295,"depth":95,"text":884},"get vs  and setdefault",{"id":482,"depth":95,"text":483},{"id":623,"depth":95,"text":624},{"id":745,"depth":95,"text":746},{"id":816,"depth":95,"text":817},"How Python dictionaries work — insertion ordering since 3.7, get vs setdefault, merging with the union operator, keys\u002Fvalues\u002Fitems views, hashable keys, and O(1) lookups.","medium","md","Python",{},"\u002Fblog\u002Fpython-dictionaries-explained","\u002Fpython\u002Fdata-structures\u002Fdictionaries",{"title":5,"description":889},"blog\u002Fpython-dictionaries-explained","Dictionaries","Data Structures","data-structures","2026-06-19","JE9xuK0XwEw8gLJq_SLRnytU3sjimrVjmqVdvbL3VVw",1781808673081]