[{"data":1,"prerenderedAt":3312},["ShallowReactive",2],{"page-\u002Fpython\u002F08-dictionaries-and-sets":3},{"id":4,"title":5,"body":6,"description":27,"extension":3306,"meta":3307,"navigation":75,"path":3308,"seo":3309,"stem":3310,"__hash__":3311},"content\u002Fpython\u002F08-dictionaries-and-sets.md","08 — Dictionaries & Sets",{"type":7,"value":8,"toc":3285},"minimark",[9,13,18,798,803,974,995,1080,1084,1284,1294,1301,1642,1649,1698,1735,1739,2017,2021,2252,2256,2371,2375,2394,2509,2523,2527,2626,2644,2757,2761,2836,2840,2926,2930,2936,3152,3223,3227,3281],[10,11,5],"h1",{"id":12},"_08-dictionaries-sets",[14,15,17],"h2",{"id":16},"hash-table-internals-open-addressing-since-36","Hash Table Internals — Open Addressing Since 3.6",[19,20,22],"code-wrapper",{"language":21},"python",[23,24,28],"pre",{"className":25,"code":26,"language":21,"meta":27,"style":27},"language-python shiki shiki-themes github-light github-dark","# ── CPython 3.6+ dict implementation: compact hash tables ──\n# Unlike traditional hash maps (separate chaining with linked lists),\n# CPython uses OPEN ADDRESSING with a two-array layout:\n#   1. An index array (hash → slot) — sparse, ~1\u002F3 to 2\u002F3 full\n#   2. A dense entries array (hash, key, value) — compact, insertion-ordered\n# This is why dicts preserve insertion order AND use less memory than older dicts.\n\nimport sys\n\n# The hash table's load factor triggers a resize — observable via size jumps\nd = {}\nprev_size = sys.getsizeof(d)\nfor i in range(20):\n    d[i] = i * 2\n    size = sys.getsizeof(d)\n    if size != prev_size:\n        print(f\"resize at len={len(d):>3}: {prev_size} → {size} bytes\")\n        prev_size = size\n# Resize happens at ~2\u002F3 load factor — capacity roughly doubles each time\n\n# ── Hash collisions: equal values MUST hash equally ──\n# Python's numeric tower: 1 == 1.0 == True are all equal, so they hash identically\nprint(hash(1) == hash(1.0) == hash(True))   # True — all three are the \"same\" key in a dict\u002Fset\nprint({1, 1.0, True})                       # {1} — collapses to ONE element (first inserted wins)\n\n# ANTI-PATTERN: using 1 and True (or 0 and False) as distinct dict keys\nconfig = {1: \"integer value\", True: \"boolean value\"}\nprint(config)   # {1: 'boolean value'} — True overwrote 1! They're the same key!\n\n# ── Production: a bounded LRU cache built on dict ordering (3.7+) ──\n# Insertion-order preservation makes OrderedDict\u002Fdict a natural LRU substrate\nfrom collections import OrderedDict\n\nclass LRUCache:\n    \"\"\"Least-recently-used cache with O(1) get\u002Fset — production pattern.\"\"\"\n    def __init__(self, capacity: int):\n        self.capacity = capacity\n        self._store: OrderedDict = OrderedDict()\n\n    def get(self, key):\n        \"\"\"Return value and mark as most-recently-used, or None on miss.\"\"\"\n        if key not in self._store:\n            return None\n        self._store.move_to_end(key)   # move to tail = most recently used\n        return self._store[key]\n\n    def put(self, key, value):\n        \"\"\"Insert\u002Fupdate key. Evicts LRU entry if over capacity.\"\"\"\n        if key in self._store:\n            self._store.move_to_end(key)   # update = also marks as MRU\n        self._store[key] = value\n        if len(self._store) > self.capacity:\n            self._store.popitem(last=False)   # pop from HEAD = least recently used\n\ncache = LRUCache(3)\ncache.put(\"a\", 1); cache.put(\"b\", 2); cache.put(\"c\", 3)\ncache.get(\"a\")         # \"a\" is now MRU\ncache.put(\"d\", 4)      # evicts \"b\" (LRU), not \"a\" (was accessed)\nprint(cache.get(\"b\"))  # None — evicted\nprint(cache.get(\"a\"))  # 1 — still present\n","",[29,30,31,40,46,52,58,64,70,77,88,93,99,111,122,147,163,173,188,242,253,259,264,270,276,323,348,353,359,389,400,405,411,417,431,436,449,455,472,486,499,504,515,521,542,551,562,573,578,589,595,608,619,632,656,679,684,700,735,749,768,784],"code",{"__ignoreMap":27},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sdCPZ","# ── CPython 3.6+ dict implementation: compact hash tables ──\n",[32,41,43],{"class":34,"line":42},2,[32,44,45],{"class":38},"# Unlike traditional hash maps (separate chaining with linked lists),\n",[32,47,49],{"class":34,"line":48},3,[32,50,51],{"class":38},"# CPython uses OPEN ADDRESSING with a two-array layout:\n",[32,53,55],{"class":34,"line":54},4,[32,56,57],{"class":38},"#   1. An index array (hash → slot) — sparse, ~1\u002F3 to 2\u002F3 full\n",[32,59,61],{"class":34,"line":60},5,[32,62,63],{"class":38},"#   2. A dense entries array (hash, key, value) — compact, insertion-ordered\n",[32,65,67],{"class":34,"line":66},6,[32,68,69],{"class":38},"# This is why dicts preserve insertion order AND use less memory than older dicts.\n",[32,71,73],{"class":34,"line":72},7,[32,74,76],{"emptyLinePlaceholder":75},true,"\n",[32,78,80,84],{"class":34,"line":79},8,[32,81,83],{"class":82},"svdQ7","import",[32,85,87],{"class":86},"ssxIu"," sys\n",[32,89,91],{"class":34,"line":90},9,[32,92,76],{"emptyLinePlaceholder":75},[32,94,96],{"class":34,"line":95},10,[32,97,98],{"class":38},"# The hash table's load factor triggers a resize — observable via size jumps\n",[32,100,102,105,108],{"class":34,"line":101},11,[32,103,104],{"class":86},"d ",[32,106,107],{"class":82},"=",[32,109,110],{"class":86}," {}\n",[32,112,114,117,119],{"class":34,"line":113},12,[32,115,116],{"class":86},"prev_size ",[32,118,107],{"class":82},[32,120,121],{"class":86}," sys.getsizeof(d)\n",[32,123,125,128,131,134,138,141,144],{"class":34,"line":124},13,[32,126,127],{"class":82},"for",[32,129,130],{"class":86}," i ",[32,132,133],{"class":82},"in",[32,135,137],{"class":136},"snvgF"," range",[32,139,140],{"class":86},"(",[32,142,143],{"class":136},"20",[32,145,146],{"class":86},"):\n",[32,148,150,153,155,157,160],{"class":34,"line":149},14,[32,151,152],{"class":86},"    d[i] ",[32,154,107],{"class":82},[32,156,130],{"class":86},[32,158,159],{"class":82},"*",[32,161,162],{"class":136}," 2\n",[32,164,166,169,171],{"class":34,"line":165},15,[32,167,168],{"class":86},"    size ",[32,170,107],{"class":82},[32,172,121],{"class":86},[32,174,176,179,182,185],{"class":34,"line":175},16,[32,177,178],{"class":82},"    if",[32,180,181],{"class":86}," size ",[32,183,184],{"class":82},"!=",[32,186,187],{"class":86}," prev_size:\n",[32,189,191,194,196,199,203,206,209,212,215,218,221,224,226,229,231,234,236,239],{"class":34,"line":190},17,[32,192,193],{"class":136},"        print",[32,195,140],{"class":86},[32,197,198],{"class":82},"f",[32,200,202],{"class":201},"sJ6F3","\"resize at len=",[32,204,205],{"class":136},"{len",[32,207,208],{"class":86},"(d)",[32,210,211],{"class":82},":>3",[32,213,214],{"class":136},"}",[32,216,217],{"class":201},": ",[32,219,220],{"class":136},"{",[32,222,223],{"class":86},"prev_size",[32,225,214],{"class":136},[32,227,228],{"class":201}," → ",[32,230,220],{"class":136},[32,232,233],{"class":86},"size",[32,235,214],{"class":136},[32,237,238],{"class":201}," bytes\"",[32,240,241],{"class":86},")\n",[32,243,245,248,250],{"class":34,"line":244},18,[32,246,247],{"class":86},"        prev_size ",[32,249,107],{"class":82},[32,251,252],{"class":86}," size\n",[32,254,256],{"class":34,"line":255},19,[32,257,258],{"class":38},"# Resize happens at ~2\u002F3 load factor — capacity roughly doubles each time\n",[32,260,262],{"class":34,"line":261},20,[32,263,76],{"emptyLinePlaceholder":75},[32,265,267],{"class":34,"line":266},21,[32,268,269],{"class":38},"# ── Hash collisions: equal values MUST hash equally ──\n",[32,271,273],{"class":34,"line":272},22,[32,274,275],{"class":38},"# Python's numeric tower: 1 == 1.0 == True are all equal, so they hash identically\n",[32,277,279,282,284,287,289,292,295,298,301,303,306,308,310,312,314,317,320],{"class":34,"line":278},23,[32,280,281],{"class":136},"print",[32,283,140],{"class":86},[32,285,286],{"class":136},"hash",[32,288,140],{"class":86},[32,290,291],{"class":136},"1",[32,293,294],{"class":86},") ",[32,296,297],{"class":82},"==",[32,299,300],{"class":136}," hash",[32,302,140],{"class":86},[32,304,305],{"class":136},"1.0",[32,307,294],{"class":86},[32,309,297],{"class":82},[32,311,300],{"class":136},[32,313,140],{"class":86},[32,315,316],{"class":136},"True",[32,318,319],{"class":86},"))   ",[32,321,322],{"class":38},"# True — all three are the \"same\" key in a dict\u002Fset\n",[32,324,326,328,331,333,336,338,340,342,345],{"class":34,"line":325},24,[32,327,281],{"class":136},[32,329,330],{"class":86},"({",[32,332,291],{"class":136},[32,334,335],{"class":86},", ",[32,337,305],{"class":136},[32,339,335],{"class":86},[32,341,316],{"class":136},[32,343,344],{"class":86},"})                       ",[32,346,347],{"class":38},"# {1} — collapses to ONE element (first inserted wins)\n",[32,349,351],{"class":34,"line":350},25,[32,352,76],{"emptyLinePlaceholder":75},[32,354,356],{"class":34,"line":355},26,[32,357,358],{"class":38},"# ANTI-PATTERN: using 1 and True (or 0 and False) as distinct dict keys\n",[32,360,362,365,367,370,372,374,377,379,381,383,386],{"class":34,"line":361},27,[32,363,364],{"class":86},"config ",[32,366,107],{"class":82},[32,368,369],{"class":86}," {",[32,371,291],{"class":136},[32,373,217],{"class":86},[32,375,376],{"class":201},"\"integer value\"",[32,378,335],{"class":86},[32,380,316],{"class":136},[32,382,217],{"class":86},[32,384,385],{"class":201},"\"boolean value\"",[32,387,388],{"class":86},"}\n",[32,390,392,394,397],{"class":34,"line":391},28,[32,393,281],{"class":136},[32,395,396],{"class":86},"(config)   ",[32,398,399],{"class":38},"# {1: 'boolean value'} — True overwrote 1! They're the same key!\n",[32,401,403],{"class":34,"line":402},29,[32,404,76],{"emptyLinePlaceholder":75},[32,406,408],{"class":34,"line":407},30,[32,409,410],{"class":38},"# ── Production: a bounded LRU cache built on dict ordering (3.7+) ──\n",[32,412,414],{"class":34,"line":413},31,[32,415,416],{"class":38},"# Insertion-order preservation makes OrderedDict\u002Fdict a natural LRU substrate\n",[32,418,420,423,426,428],{"class":34,"line":419},32,[32,421,422],{"class":82},"from",[32,424,425],{"class":86}," collections ",[32,427,83],{"class":82},[32,429,430],{"class":86}," OrderedDict\n",[32,432,434],{"class":34,"line":433},33,[32,435,76],{"emptyLinePlaceholder":75},[32,437,439,442,446],{"class":34,"line":438},34,[32,440,441],{"class":82},"class",[32,443,445],{"class":444},"sIsaT"," LRUCache",[32,447,448],{"class":86},":\n",[32,450,452],{"class":34,"line":451},35,[32,453,454],{"class":201},"    \"\"\"Least-recently-used cache with O(1) get\u002Fset — production pattern.\"\"\"\n",[32,456,458,461,464,467,470],{"class":34,"line":457},36,[32,459,460],{"class":82},"    def",[32,462,463],{"class":136}," __init__",[32,465,466],{"class":86},"(self, capacity: ",[32,468,469],{"class":136},"int",[32,471,146],{"class":86},[32,473,475,478,481,483],{"class":34,"line":474},37,[32,476,477],{"class":136},"        self",[32,479,480],{"class":86},".capacity ",[32,482,107],{"class":82},[32,484,485],{"class":86}," capacity\n",[32,487,489,491,494,496],{"class":34,"line":488},38,[32,490,477],{"class":136},[32,492,493],{"class":86},"._store: OrderedDict ",[32,495,107],{"class":82},[32,497,498],{"class":86}," OrderedDict()\n",[32,500,502],{"class":34,"line":501},39,[32,503,76],{"emptyLinePlaceholder":75},[32,505,507,509,512],{"class":34,"line":506},40,[32,508,460],{"class":82},[32,510,511],{"class":444}," get",[32,513,514],{"class":86},"(self, key):\n",[32,516,518],{"class":34,"line":517},41,[32,519,520],{"class":201},"        \"\"\"Return value and mark as most-recently-used, or None on miss.\"\"\"\n",[32,522,524,527,530,533,536,539],{"class":34,"line":523},42,[32,525,526],{"class":82},"        if",[32,528,529],{"class":86}," key ",[32,531,532],{"class":82},"not",[32,534,535],{"class":82}," in",[32,537,538],{"class":136}," self",[32,540,541],{"class":86},"._store:\n",[32,543,545,548],{"class":34,"line":544},43,[32,546,547],{"class":82},"            return",[32,549,550],{"class":136}," None\n",[32,552,554,556,559],{"class":34,"line":553},44,[32,555,477],{"class":136},[32,557,558],{"class":86},"._store.move_to_end(key)   ",[32,560,561],{"class":38},"# move to tail = most recently used\n",[32,563,565,568,570],{"class":34,"line":564},45,[32,566,567],{"class":82},"        return",[32,569,538],{"class":136},[32,571,572],{"class":86},"._store[key]\n",[32,574,576],{"class":34,"line":575},46,[32,577,76],{"emptyLinePlaceholder":75},[32,579,581,583,586],{"class":34,"line":580},47,[32,582,460],{"class":82},[32,584,585],{"class":444}," put",[32,587,588],{"class":86},"(self, key, value):\n",[32,590,592],{"class":34,"line":591},48,[32,593,594],{"class":201},"        \"\"\"Insert\u002Fupdate key. Evicts LRU entry if over capacity.\"\"\"\n",[32,596,598,600,602,604,606],{"class":34,"line":597},49,[32,599,526],{"class":82},[32,601,529],{"class":86},[32,603,133],{"class":82},[32,605,538],{"class":136},[32,607,541],{"class":86},[32,609,611,614,616],{"class":34,"line":610},50,[32,612,613],{"class":136},"            self",[32,615,558],{"class":86},[32,617,618],{"class":38},"# update = also marks as MRU\n",[32,620,622,624,627,629],{"class":34,"line":621},51,[32,623,477],{"class":136},[32,625,626],{"class":86},"._store[key] ",[32,628,107],{"class":82},[32,630,631],{"class":86}," value\n",[32,633,635,637,640,642,645,648,651,653],{"class":34,"line":634},52,[32,636,526],{"class":82},[32,638,639],{"class":136}," len",[32,641,140],{"class":86},[32,643,644],{"class":136},"self",[32,646,647],{"class":86},"._store) ",[32,649,650],{"class":82},">",[32,652,538],{"class":136},[32,654,655],{"class":86},".capacity:\n",[32,657,659,661,664,668,670,673,676],{"class":34,"line":658},53,[32,660,613],{"class":136},[32,662,663],{"class":86},"._store.popitem(",[32,665,667],{"class":666},"sCrzJ","last",[32,669,107],{"class":82},[32,671,672],{"class":136},"False",[32,674,675],{"class":86},")   ",[32,677,678],{"class":38},"# pop from HEAD = least recently used\n",[32,680,682],{"class":34,"line":681},54,[32,683,76],{"emptyLinePlaceholder":75},[32,685,687,690,692,695,698],{"class":34,"line":686},55,[32,688,689],{"class":86},"cache ",[32,691,107],{"class":82},[32,693,694],{"class":86}," LRUCache(",[32,696,697],{"class":136},"3",[32,699,241],{"class":86},[32,701,703,706,709,711,713,716,719,721,724,726,729,731,733],{"class":34,"line":702},56,[32,704,705],{"class":86},"cache.put(",[32,707,708],{"class":201},"\"a\"",[32,710,335],{"class":86},[32,712,291],{"class":136},[32,714,715],{"class":86},"); cache.put(",[32,717,718],{"class":201},"\"b\"",[32,720,335],{"class":86},[32,722,723],{"class":136},"2",[32,725,715],{"class":86},[32,727,728],{"class":201},"\"c\"",[32,730,335],{"class":86},[32,732,697],{"class":136},[32,734,241],{"class":86},[32,736,738,741,743,746],{"class":34,"line":737},57,[32,739,740],{"class":86},"cache.get(",[32,742,708],{"class":201},[32,744,745],{"class":86},")         ",[32,747,748],{"class":38},"# \"a\" is now MRU\n",[32,750,752,754,757,759,762,765],{"class":34,"line":751},58,[32,753,705],{"class":86},[32,755,756],{"class":201},"\"d\"",[32,758,335],{"class":86},[32,760,761],{"class":136},"4",[32,763,764],{"class":86},")      ",[32,766,767],{"class":38},"# evicts \"b\" (LRU), not \"a\" (was accessed)\n",[32,769,771,773,776,778,781],{"class":34,"line":770},59,[32,772,281],{"class":136},[32,774,775],{"class":86},"(cache.get(",[32,777,718],{"class":201},[32,779,780],{"class":86},"))  ",[32,782,783],{"class":38},"# None — evicted\n",[32,785,787,789,791,793,795],{"class":34,"line":786},60,[32,788,281],{"class":136},[32,790,775],{"class":86},[32,792,708],{"class":201},[32,794,780],{"class":86},[32,796,797],{"class":38},"# 1 — still present\n",[799,800,802],"h3",{"id":801},"iterating-dictionaries","Iterating dictionaries",[19,804,805],{"language":21},[23,806,808],{"className":25,"code":807,"language":21,"meta":27,"style":27},"scores = {\"Ada\": 98, \"Grace\": 95, \"Alan\": 87}\n\nfor key in scores:                 # iterates KEYS by default\n    print(key)\n\nfor key, value in scores.items():    # keys AND values\n    print(key, value)\n\nfor value in scores.values():          # values only\n    print(value)\n\nprint(list(scores.keys()))               # ['Ada', 'Grace', 'Alan']\nprint(list(scores.values()))               # [98, 95, 87]\nprint(list(scores.items()))                  # [('Ada', 98), ('Grace', 95), ('Alan', 87)]\n",[29,809,810,849,853,867,875,879,894,901,905,920,927,931,946,960],{"__ignoreMap":27},[32,811,812,815,817,819,822,824,827,829,832,834,837,839,842,844,847],{"class":34,"line":35},[32,813,814],{"class":86},"scores ",[32,816,107],{"class":82},[32,818,369],{"class":86},[32,820,821],{"class":201},"\"Ada\"",[32,823,217],{"class":86},[32,825,826],{"class":136},"98",[32,828,335],{"class":86},[32,830,831],{"class":201},"\"Grace\"",[32,833,217],{"class":86},[32,835,836],{"class":136},"95",[32,838,335],{"class":86},[32,840,841],{"class":201},"\"Alan\"",[32,843,217],{"class":86},[32,845,846],{"class":136},"87",[32,848,388],{"class":86},[32,850,851],{"class":34,"line":42},[32,852,76],{"emptyLinePlaceholder":75},[32,854,855,857,859,861,864],{"class":34,"line":48},[32,856,127],{"class":82},[32,858,529],{"class":86},[32,860,133],{"class":82},[32,862,863],{"class":86}," scores:                 ",[32,865,866],{"class":38},"# iterates KEYS by default\n",[32,868,869,872],{"class":34,"line":54},[32,870,871],{"class":136},"    print",[32,873,874],{"class":86},"(key)\n",[32,876,877],{"class":34,"line":60},[32,878,76],{"emptyLinePlaceholder":75},[32,880,881,883,886,888,891],{"class":34,"line":66},[32,882,127],{"class":82},[32,884,885],{"class":86}," key, value ",[32,887,133],{"class":82},[32,889,890],{"class":86}," scores.items():    ",[32,892,893],{"class":38},"# keys AND values\n",[32,895,896,898],{"class":34,"line":72},[32,897,871],{"class":136},[32,899,900],{"class":86},"(key, value)\n",[32,902,903],{"class":34,"line":79},[32,904,76],{"emptyLinePlaceholder":75},[32,906,907,909,912,914,917],{"class":34,"line":90},[32,908,127],{"class":82},[32,910,911],{"class":86}," value ",[32,913,133],{"class":82},[32,915,916],{"class":86}," scores.values():          ",[32,918,919],{"class":38},"# values only\n",[32,921,922,924],{"class":34,"line":95},[32,923,871],{"class":136},[32,925,926],{"class":86},"(value)\n",[32,928,929],{"class":34,"line":101},[32,930,76],{"emptyLinePlaceholder":75},[32,932,933,935,937,940,943],{"class":34,"line":113},[32,934,281],{"class":136},[32,936,140],{"class":86},[32,938,939],{"class":136},"list",[32,941,942],{"class":86},"(scores.keys()))               ",[32,944,945],{"class":38},"# ['Ada', 'Grace', 'Alan']\n",[32,947,948,950,952,954,957],{"class":34,"line":124},[32,949,281],{"class":136},[32,951,140],{"class":86},[32,953,939],{"class":136},[32,955,956],{"class":86},"(scores.values()))               ",[32,958,959],{"class":38},"# [98, 95, 87]\n",[32,961,962,964,966,968,971],{"class":34,"line":149},[32,963,281],{"class":136},[32,965,140],{"class":86},[32,967,939],{"class":136},[32,969,970],{"class":86},"(scores.items()))                  ",[32,972,973],{"class":38},"# [('Ada', 98), ('Grace', 95), ('Alan', 87)]\n",[975,976,977,217,981,335,984,335,987,990,991,994],"p",{},[978,979,980],"strong",{},"Gotcha",[29,982,983],{},".keys()",[29,985,986],{},".values()",[29,988,989],{},".items()"," return ",[978,992,993],{},"view objects",", not lists — they stay live and reflect subsequent changes to the dict, and they don't support indexing.",[19,996,997],{"language":21},[23,998,1000],{"className":25,"code":999,"language":21,"meta":27,"style":27},"d = {\"a\": 1, \"b\": 2}\nkeys_view = d.keys()\nprint(keys_view)      # dict_keys(['a', 'b'])\nd[\"c\"] = 3\nprint(keys_view)         # dict_keys(['a', 'b', 'c']) — the VIEW updated automatically!\n\n# keys_view[0]   # TypeError: 'dict_keys' object is not subscriptable\n",[29,1001,1002,1026,1036,1046,1061,1071,1075],{"__ignoreMap":27},[32,1003,1004,1006,1008,1010,1012,1014,1016,1018,1020,1022,1024],{"class":34,"line":35},[32,1005,104],{"class":86},[32,1007,107],{"class":82},[32,1009,369],{"class":86},[32,1011,708],{"class":201},[32,1013,217],{"class":86},[32,1015,291],{"class":136},[32,1017,335],{"class":86},[32,1019,718],{"class":201},[32,1021,217],{"class":86},[32,1023,723],{"class":136},[32,1025,388],{"class":86},[32,1027,1028,1031,1033],{"class":34,"line":42},[32,1029,1030],{"class":86},"keys_view ",[32,1032,107],{"class":82},[32,1034,1035],{"class":86}," d.keys()\n",[32,1037,1038,1040,1043],{"class":34,"line":48},[32,1039,281],{"class":136},[32,1041,1042],{"class":86},"(keys_view)      ",[32,1044,1045],{"class":38},"# dict_keys(['a', 'b'])\n",[32,1047,1048,1051,1053,1056,1058],{"class":34,"line":54},[32,1049,1050],{"class":86},"d[",[32,1052,728],{"class":201},[32,1054,1055],{"class":86},"] ",[32,1057,107],{"class":82},[32,1059,1060],{"class":136}," 3\n",[32,1062,1063,1065,1068],{"class":34,"line":60},[32,1064,281],{"class":136},[32,1066,1067],{"class":86},"(keys_view)         ",[32,1069,1070],{"class":38},"# dict_keys(['a', 'b', 'c']) — the VIEW updated automatically!\n",[32,1072,1073],{"class":34,"line":66},[32,1074,76],{"emptyLinePlaceholder":75},[32,1076,1077],{"class":34,"line":72},[32,1078,1079],{"class":38},"# keys_view[0]   # TypeError: 'dict_keys' object is not subscriptable\n",[14,1081,1083],{"id":1082},"merging-dictionaries","Merging Dictionaries",[19,1085,1086],{"language":21},[23,1087,1089],{"className":25,"code":1088,"language":21,"meta":27,"style":27},"defaults = {\"theme\": \"light\", \"notifications\": True}\nuser_prefs = {\"theme\": \"dark\"}\n\n# Python 3.9+ — the | merge operator (does NOT mutate either operand)\nmerged = defaults | user_prefs\nprint(merged)   # {'theme': 'dark', 'notifications': True}  — right side wins on conflict\n\n# |= for in-place merge\nsettings = dict(defaults)\nsettings |= user_prefs\nprint(settings)   # {'theme': 'dark', 'notifications': True}\n\n# Pre-3.9 idiom — still extremely common in real code\nmerged_old = {**defaults, **user_prefs}\nprint(merged_old)   # same result\n\n# .update() — mutates the receiver in place\ncombined = dict(defaults)\ncombined.update(user_prefs)\nprint(combined)\n",[29,1090,1091,1119,1137,1141,1146,1162,1172,1176,1181,1194,1203,1213,1217,1222,1242,1252,1256,1261,1272,1277],{"__ignoreMap":27},[32,1092,1093,1096,1098,1100,1103,1105,1108,1110,1113,1115,1117],{"class":34,"line":35},[32,1094,1095],{"class":86},"defaults ",[32,1097,107],{"class":82},[32,1099,369],{"class":86},[32,1101,1102],{"class":201},"\"theme\"",[32,1104,217],{"class":86},[32,1106,1107],{"class":201},"\"light\"",[32,1109,335],{"class":86},[32,1111,1112],{"class":201},"\"notifications\"",[32,1114,217],{"class":86},[32,1116,316],{"class":136},[32,1118,388],{"class":86},[32,1120,1121,1124,1126,1128,1130,1132,1135],{"class":34,"line":42},[32,1122,1123],{"class":86},"user_prefs ",[32,1125,107],{"class":82},[32,1127,369],{"class":86},[32,1129,1102],{"class":201},[32,1131,217],{"class":86},[32,1133,1134],{"class":201},"\"dark\"",[32,1136,388],{"class":86},[32,1138,1139],{"class":34,"line":48},[32,1140,76],{"emptyLinePlaceholder":75},[32,1142,1143],{"class":34,"line":54},[32,1144,1145],{"class":38},"# Python 3.9+ — the | merge operator (does NOT mutate either operand)\n",[32,1147,1148,1151,1153,1156,1159],{"class":34,"line":60},[32,1149,1150],{"class":86},"merged ",[32,1152,107],{"class":82},[32,1154,1155],{"class":86}," defaults ",[32,1157,1158],{"class":82},"|",[32,1160,1161],{"class":86}," user_prefs\n",[32,1163,1164,1166,1169],{"class":34,"line":66},[32,1165,281],{"class":136},[32,1167,1168],{"class":86},"(merged)   ",[32,1170,1171],{"class":38},"# {'theme': 'dark', 'notifications': True}  — right side wins on conflict\n",[32,1173,1174],{"class":34,"line":72},[32,1175,76],{"emptyLinePlaceholder":75},[32,1177,1178],{"class":34,"line":79},[32,1179,1180],{"class":38},"# |= for in-place merge\n",[32,1182,1183,1186,1188,1191],{"class":34,"line":90},[32,1184,1185],{"class":86},"settings ",[32,1187,107],{"class":82},[32,1189,1190],{"class":136}," dict",[32,1192,1193],{"class":86},"(defaults)\n",[32,1195,1196,1198,1201],{"class":34,"line":95},[32,1197,1185],{"class":86},[32,1199,1200],{"class":82},"|=",[32,1202,1161],{"class":86},[32,1204,1205,1207,1210],{"class":34,"line":101},[32,1206,281],{"class":136},[32,1208,1209],{"class":86},"(settings)   ",[32,1211,1212],{"class":38},"# {'theme': 'dark', 'notifications': True}\n",[32,1214,1215],{"class":34,"line":113},[32,1216,76],{"emptyLinePlaceholder":75},[32,1218,1219],{"class":34,"line":124},[32,1220,1221],{"class":38},"# Pre-3.9 idiom — still extremely common in real code\n",[32,1223,1224,1227,1229,1231,1234,1237,1239],{"class":34,"line":149},[32,1225,1226],{"class":86},"merged_old ",[32,1228,107],{"class":82},[32,1230,369],{"class":86},[32,1232,1233],{"class":82},"**",[32,1235,1236],{"class":86},"defaults, ",[32,1238,1233],{"class":82},[32,1240,1241],{"class":86},"user_prefs}\n",[32,1243,1244,1246,1249],{"class":34,"line":165},[32,1245,281],{"class":136},[32,1247,1248],{"class":86},"(merged_old)   ",[32,1250,1251],{"class":38},"# same result\n",[32,1253,1254],{"class":34,"line":175},[32,1255,76],{"emptyLinePlaceholder":75},[32,1257,1258],{"class":34,"line":190},[32,1259,1260],{"class":38},"# .update() — mutates the receiver in place\n",[32,1262,1263,1266,1268,1270],{"class":34,"line":244},[32,1264,1265],{"class":86},"combined ",[32,1267,107],{"class":82},[32,1269,1190],{"class":136},[32,1271,1193],{"class":86},[32,1273,1274],{"class":34,"line":255},[32,1275,1276],{"class":86},"combined.update(user_prefs)\n",[32,1278,1279,1281],{"class":34,"line":261},[32,1280,281],{"class":136},[32,1282,1283],{"class":86},"(combined)\n",[14,1285,1287,1290,1291],{"id":1286},"defaultdict-and-counter",[29,1288,1289],{},"defaultdict"," and ",[29,1292,1293],{},"Counter",[975,1295,1296,1297,1300],{},"Two of the most-used tools from ",[29,1298,1299],{},"collections"," for real-world data wrangling.",[19,1302,1303],{"language":21},[23,1304,1306],{"className":25,"code":1305,"language":21,"meta":27,"style":27},"from collections import defaultdict, Counter\n\n# defaultdict — auto-creates a default value for missing keys, avoiding\n# verbose \"if key not in d: d[key] = []\" boilerplate\ngroups = defaultdict(list)\nwords = [\"apple\", \"banana\", \"avocado\", \"blueberry\", \"cherry\"]\nfor word in words:\n    groups[word[0]].append(word)     # no KeyError, no manual initialization\n\nprint(dict(groups))\n# {'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}\n\n# Counter — a dict subclass specialized for counting hashable items\ncounts = Counter(\"mississippi\")\nprint(counts)                # Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})\nprint(counts.most_common(2))    # [('i', 4), ('s', 4)]\n\nword_counts = Counter([\"cat\", \"dog\", \"cat\", \"bird\", \"dog\", \"cat\"])\nprint(word_counts[\"cat\"])         # 3\nprint(word_counts[\"fish\"])          # 0 — missing keys return 0, NOT KeyError!\n\n# Counter arithmetic\nc1 = Counter(a=3, b=1)\nc2 = Counter(a=1, b=2)\nprint(c1 + c2)   # Counter({'a': 4, 'b': 3})\nprint(c1 - c2)   # Counter({'a': 2}) — subtraction drops non-positive counts\n",[29,1307,1308,1319,1323,1328,1333,1347,1383,1395,1409,1413,1425,1430,1434,1439,1454,1464,1479,1483,1521,1536,1551,1555,1560,1587,1612,1628],{"__ignoreMap":27},[32,1309,1310,1312,1314,1316],{"class":34,"line":35},[32,1311,422],{"class":82},[32,1313,425],{"class":86},[32,1315,83],{"class":82},[32,1317,1318],{"class":86}," defaultdict, Counter\n",[32,1320,1321],{"class":34,"line":42},[32,1322,76],{"emptyLinePlaceholder":75},[32,1324,1325],{"class":34,"line":48},[32,1326,1327],{"class":38},"# defaultdict — auto-creates a default value for missing keys, avoiding\n",[32,1329,1330],{"class":34,"line":54},[32,1331,1332],{"class":38},"# verbose \"if key not in d: d[key] = []\" boilerplate\n",[32,1334,1335,1338,1340,1343,1345],{"class":34,"line":60},[32,1336,1337],{"class":86},"groups ",[32,1339,107],{"class":82},[32,1341,1342],{"class":86}," defaultdict(",[32,1344,939],{"class":136},[32,1346,241],{"class":86},[32,1348,1349,1352,1354,1357,1360,1362,1365,1367,1370,1372,1375,1377,1380],{"class":34,"line":66},[32,1350,1351],{"class":86},"words ",[32,1353,107],{"class":82},[32,1355,1356],{"class":86}," [",[32,1358,1359],{"class":201},"\"apple\"",[32,1361,335],{"class":86},[32,1363,1364],{"class":201},"\"banana\"",[32,1366,335],{"class":86},[32,1368,1369],{"class":201},"\"avocado\"",[32,1371,335],{"class":86},[32,1373,1374],{"class":201},"\"blueberry\"",[32,1376,335],{"class":86},[32,1378,1379],{"class":201},"\"cherry\"",[32,1381,1382],{"class":86},"]\n",[32,1384,1385,1387,1390,1392],{"class":34,"line":72},[32,1386,127],{"class":82},[32,1388,1389],{"class":86}," word ",[32,1391,133],{"class":82},[32,1393,1394],{"class":86}," words:\n",[32,1396,1397,1400,1403,1406],{"class":34,"line":79},[32,1398,1399],{"class":86},"    groups[word[",[32,1401,1402],{"class":136},"0",[32,1404,1405],{"class":86},"]].append(word)     ",[32,1407,1408],{"class":38},"# no KeyError, no manual initialization\n",[32,1410,1411],{"class":34,"line":90},[32,1412,76],{"emptyLinePlaceholder":75},[32,1414,1415,1417,1419,1422],{"class":34,"line":95},[32,1416,281],{"class":136},[32,1418,140],{"class":86},[32,1420,1421],{"class":136},"dict",[32,1423,1424],{"class":86},"(groups))\n",[32,1426,1427],{"class":34,"line":101},[32,1428,1429],{"class":38},"# {'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}\n",[32,1431,1432],{"class":34,"line":113},[32,1433,76],{"emptyLinePlaceholder":75},[32,1435,1436],{"class":34,"line":124},[32,1437,1438],{"class":38},"# Counter — a dict subclass specialized for counting hashable items\n",[32,1440,1441,1444,1446,1449,1452],{"class":34,"line":149},[32,1442,1443],{"class":86},"counts ",[32,1445,107],{"class":82},[32,1447,1448],{"class":86}," Counter(",[32,1450,1451],{"class":201},"\"mississippi\"",[32,1453,241],{"class":86},[32,1455,1456,1458,1461],{"class":34,"line":165},[32,1457,281],{"class":136},[32,1459,1460],{"class":86},"(counts)                ",[32,1462,1463],{"class":38},"# Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})\n",[32,1465,1466,1468,1471,1473,1476],{"class":34,"line":175},[32,1467,281],{"class":136},[32,1469,1470],{"class":86},"(counts.most_common(",[32,1472,723],{"class":136},[32,1474,1475],{"class":86},"))    ",[32,1477,1478],{"class":38},"# [('i', 4), ('s', 4)]\n",[32,1480,1481],{"class":34,"line":190},[32,1482,76],{"emptyLinePlaceholder":75},[32,1484,1485,1488,1490,1493,1496,1498,1501,1503,1505,1507,1510,1512,1514,1516,1518],{"class":34,"line":244},[32,1486,1487],{"class":86},"word_counts ",[32,1489,107],{"class":82},[32,1491,1492],{"class":86}," Counter([",[32,1494,1495],{"class":201},"\"cat\"",[32,1497,335],{"class":86},[32,1499,1500],{"class":201},"\"dog\"",[32,1502,335],{"class":86},[32,1504,1495],{"class":201},[32,1506,335],{"class":86},[32,1508,1509],{"class":201},"\"bird\"",[32,1511,335],{"class":86},[32,1513,1500],{"class":201},[32,1515,335],{"class":86},[32,1517,1495],{"class":201},[32,1519,1520],{"class":86},"])\n",[32,1522,1523,1525,1528,1530,1533],{"class":34,"line":255},[32,1524,281],{"class":136},[32,1526,1527],{"class":86},"(word_counts[",[32,1529,1495],{"class":201},[32,1531,1532],{"class":86},"])         ",[32,1534,1535],{"class":38},"# 3\n",[32,1537,1538,1540,1542,1545,1548],{"class":34,"line":261},[32,1539,281],{"class":136},[32,1541,1527],{"class":86},[32,1543,1544],{"class":201},"\"fish\"",[32,1546,1547],{"class":86},"])          ",[32,1549,1550],{"class":38},"# 0 — missing keys return 0, NOT KeyError!\n",[32,1552,1553],{"class":34,"line":266},[32,1554,76],{"emptyLinePlaceholder":75},[32,1556,1557],{"class":34,"line":272},[32,1558,1559],{"class":38},"# Counter arithmetic\n",[32,1561,1562,1565,1567,1569,1572,1574,1576,1578,1581,1583,1585],{"class":34,"line":278},[32,1563,1564],{"class":86},"c1 ",[32,1566,107],{"class":82},[32,1568,1448],{"class":86},[32,1570,1571],{"class":666},"a",[32,1573,107],{"class":82},[32,1575,697],{"class":136},[32,1577,335],{"class":86},[32,1579,1580],{"class":666},"b",[32,1582,107],{"class":82},[32,1584,291],{"class":136},[32,1586,241],{"class":86},[32,1588,1589,1592,1594,1596,1598,1600,1602,1604,1606,1608,1610],{"class":34,"line":325},[32,1590,1591],{"class":86},"c2 ",[32,1593,107],{"class":82},[32,1595,1448],{"class":86},[32,1597,1571],{"class":666},[32,1599,107],{"class":82},[32,1601,291],{"class":136},[32,1603,335],{"class":86},[32,1605,1580],{"class":666},[32,1607,107],{"class":82},[32,1609,723],{"class":136},[32,1611,241],{"class":86},[32,1613,1614,1616,1619,1622,1625],{"class":34,"line":350},[32,1615,281],{"class":136},[32,1617,1618],{"class":86},"(c1 ",[32,1620,1621],{"class":82},"+",[32,1623,1624],{"class":86}," c2)   ",[32,1626,1627],{"class":38},"# Counter({'a': 4, 'b': 3})\n",[32,1629,1630,1632,1634,1637,1639],{"class":34,"line":355},[32,1631,281],{"class":136},[32,1633,1618],{"class":86},[32,1635,1636],{"class":82},"-",[32,1638,1624],{"class":86},[32,1640,1641],{"class":38},"# Counter({'a': 2}) — subtraction drops non-positive counts\n",[799,1643,1645,1646,1648],{"id":1644},"the-defaultdict-factory-function-gotcha","The ",[29,1647,1289],{}," factory-function gotcha",[19,1650,1651],{"language":21},[23,1652,1654],{"className":25,"code":1653,"language":21,"meta":27,"style":27},"d = defaultdict(list)\nprint(d[\"missing\"])    # [] — accessing a missing key CREATES it as a side effect!\nprint(list(d.keys()))    # ['missing']  — now actually in the dict, from a mere READ\n",[29,1655,1656,1668,1684],{"__ignoreMap":27},[32,1657,1658,1660,1662,1664,1666],{"class":34,"line":35},[32,1659,104],{"class":86},[32,1661,107],{"class":82},[32,1663,1342],{"class":86},[32,1665,939],{"class":136},[32,1667,241],{"class":86},[32,1669,1670,1672,1675,1678,1681],{"class":34,"line":42},[32,1671,281],{"class":136},[32,1673,1674],{"class":86},"(d[",[32,1676,1677],{"class":201},"\"missing\"",[32,1679,1680],{"class":86},"])    ",[32,1682,1683],{"class":38},"# [] — accessing a missing key CREATES it as a side effect!\n",[32,1685,1686,1688,1690,1692,1695],{"class":34,"line":48},[32,1687,281],{"class":136},[32,1689,140],{"class":86},[32,1691,939],{"class":136},[32,1693,1694],{"class":86},"(d.keys()))    ",[32,1696,1697],{"class":38},"# ['missing']  — now actually in the dict, from a mere READ\n",[975,1699,1700,1703,1704,1708,1709,1712,1713,1715,1716,1719,1720,1722,1723,1726,1727,1730,1731,1734],{},[978,1701,1702],{},"This surprises many developers",": simply ",[1705,1706,1707],"em",{},"reading"," ",[29,1710,1711],{},"d[key]"," on a ",[29,1714,1289],{}," inserts ",[29,1717,1718],{},"key"," into the dict if it was absent — a read has a mutating side effect, unlike a normal dict where ",[29,1721,1711],{}," on a missing key raises ",[29,1724,1725],{},"KeyError"," and touches nothing. This matters if you later check ",[29,1728,1729],{},"len(d)"," or iterate ",[29,1732,1733],{},"d"," expecting only keys you explicitly set.",[14,1736,1738],{"id":1737},"dictionary-and-set-comprehensions","Dictionary and Set Comprehensions",[19,1740,1741],{"language":21},[23,1742,1744],{"className":25,"code":1743,"language":21,"meta":27,"style":27},"# Dict comprehension\nsquares = {x: x ** 2 for x in range(6)}\nprint(squares)   # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}\n\n# Invert a dict (only safe if values are unique AND hashable)\noriginal = {\"a\": 1, \"b\": 2, \"c\": 3}\ninverted = {v: k for k, v in original.items()}\nprint(inverted)   # {1: 'a', 2: 'b', 3: 'c'}\n\n# Filter while building\nprices = {\"apple\": 1.5, \"bread\": 3.0, \"milk\": 2.5}\naffordable = {item: price for item, price in prices.items() if price \u003C 3.0}\nprint(affordable)   # {'apple': 1.5, 'milk': 2.5}\n\n# Set comprehension\nunique_lengths = {len(word) for word in [\"cat\", \"dog\", \"bird\", \"ox\"]}\nprint(unique_lengths)   # {3, 4, 2}  — duplicates (cat\u002Fdog both len 3) collapse automatically\n",[29,1745,1746,1751,1784,1794,1798,1803,1836,1856,1866,1870,1875,1913,1947,1957,1961,1966,2007],{"__ignoreMap":27},[32,1747,1748],{"class":34,"line":35},[32,1749,1750],{"class":38},"# Dict comprehension\n",[32,1752,1753,1756,1758,1761,1763,1766,1769,1772,1774,1776,1778,1781],{"class":34,"line":42},[32,1754,1755],{"class":86},"squares ",[32,1757,107],{"class":82},[32,1759,1760],{"class":86}," {x: x ",[32,1762,1233],{"class":82},[32,1764,1765],{"class":136}," 2",[32,1767,1768],{"class":82}," for",[32,1770,1771],{"class":86}," x ",[32,1773,133],{"class":82},[32,1775,137],{"class":136},[32,1777,140],{"class":86},[32,1779,1780],{"class":136},"6",[32,1782,1783],{"class":86},")}\n",[32,1785,1786,1788,1791],{"class":34,"line":48},[32,1787,281],{"class":136},[32,1789,1790],{"class":86},"(squares)   ",[32,1792,1793],{"class":38},"# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}\n",[32,1795,1796],{"class":34,"line":54},[32,1797,76],{"emptyLinePlaceholder":75},[32,1799,1800],{"class":34,"line":60},[32,1801,1802],{"class":38},"# Invert a dict (only safe if values are unique AND hashable)\n",[32,1804,1805,1808,1810,1812,1814,1816,1818,1820,1822,1824,1826,1828,1830,1832,1834],{"class":34,"line":66},[32,1806,1807],{"class":86},"original ",[32,1809,107],{"class":82},[32,1811,369],{"class":86},[32,1813,708],{"class":201},[32,1815,217],{"class":86},[32,1817,291],{"class":136},[32,1819,335],{"class":86},[32,1821,718],{"class":201},[32,1823,217],{"class":86},[32,1825,723],{"class":136},[32,1827,335],{"class":86},[32,1829,728],{"class":201},[32,1831,217],{"class":86},[32,1833,697],{"class":136},[32,1835,388],{"class":86},[32,1837,1838,1841,1843,1846,1848,1851,1853],{"class":34,"line":72},[32,1839,1840],{"class":86},"inverted ",[32,1842,107],{"class":82},[32,1844,1845],{"class":86}," {v: k ",[32,1847,127],{"class":82},[32,1849,1850],{"class":86}," k, v ",[32,1852,133],{"class":82},[32,1854,1855],{"class":86}," original.items()}\n",[32,1857,1858,1860,1863],{"class":34,"line":79},[32,1859,281],{"class":136},[32,1861,1862],{"class":86},"(inverted)   ",[32,1864,1865],{"class":38},"# {1: 'a', 2: 'b', 3: 'c'}\n",[32,1867,1868],{"class":34,"line":90},[32,1869,76],{"emptyLinePlaceholder":75},[32,1871,1872],{"class":34,"line":95},[32,1873,1874],{"class":38},"# Filter while building\n",[32,1876,1877,1880,1882,1884,1886,1888,1891,1893,1896,1898,1901,1903,1906,1908,1911],{"class":34,"line":101},[32,1878,1879],{"class":86},"prices ",[32,1881,107],{"class":82},[32,1883,369],{"class":86},[32,1885,1359],{"class":201},[32,1887,217],{"class":86},[32,1889,1890],{"class":136},"1.5",[32,1892,335],{"class":86},[32,1894,1895],{"class":201},"\"bread\"",[32,1897,217],{"class":86},[32,1899,1900],{"class":136},"3.0",[32,1902,335],{"class":86},[32,1904,1905],{"class":201},"\"milk\"",[32,1907,217],{"class":86},[32,1909,1910],{"class":136},"2.5",[32,1912,388],{"class":86},[32,1914,1915,1918,1920,1923,1925,1928,1930,1933,1936,1939,1942,1945],{"class":34,"line":113},[32,1916,1917],{"class":86},"affordable ",[32,1919,107],{"class":82},[32,1921,1922],{"class":86}," {item: price ",[32,1924,127],{"class":82},[32,1926,1927],{"class":86}," item, price ",[32,1929,133],{"class":82},[32,1931,1932],{"class":86}," prices.items() ",[32,1934,1935],{"class":82},"if",[32,1937,1938],{"class":86}," price ",[32,1940,1941],{"class":82},"\u003C",[32,1943,1944],{"class":136}," 3.0",[32,1946,388],{"class":86},[32,1948,1949,1951,1954],{"class":34,"line":124},[32,1950,281],{"class":136},[32,1952,1953],{"class":86},"(affordable)   ",[32,1955,1956],{"class":38},"# {'apple': 1.5, 'milk': 2.5}\n",[32,1958,1959],{"class":34,"line":149},[32,1960,76],{"emptyLinePlaceholder":75},[32,1962,1963],{"class":34,"line":165},[32,1964,1965],{"class":38},"# Set comprehension\n",[32,1967,1968,1971,1973,1975,1978,1981,1983,1985,1987,1989,1991,1993,1995,1997,1999,2001,2004],{"class":34,"line":175},[32,1969,1970],{"class":86},"unique_lengths ",[32,1972,107],{"class":82},[32,1974,369],{"class":86},[32,1976,1977],{"class":136},"len",[32,1979,1980],{"class":86},"(word) ",[32,1982,127],{"class":82},[32,1984,1389],{"class":86},[32,1986,133],{"class":82},[32,1988,1356],{"class":86},[32,1990,1495],{"class":201},[32,1992,335],{"class":86},[32,1994,1500],{"class":201},[32,1996,335],{"class":86},[32,1998,1509],{"class":201},[32,2000,335],{"class":86},[32,2002,2003],{"class":201},"\"ox\"",[32,2005,2006],{"class":86},"]}\n",[32,2008,2009,2011,2014],{"class":34,"line":190},[32,2010,281],{"class":136},[32,2012,2013],{"class":86},"(unique_lengths)   ",[32,2015,2016],{"class":38},"# {3, 4, 2}  — duplicates (cat\u002Fdog both len 3) collapse automatically\n",[14,2018,2020],{"id":2019},"sets-unordered-collections-of-unique-hashable-elements","Sets — Unordered Collections of Unique, Hashable Elements",[19,2022,2023],{"language":21},[23,2024,2026],{"className":25,"code":2025,"language":21,"meta":27,"style":27},"a = {1, 2, 3, 4}\nb = {3, 4, 5, 6}\n\nprint(a | b)    # {1, 2, 3, 4, 5, 6}   — union\nprint(a & b)     # {3, 4}                — intersection\nprint(a - b)      # {1, 2}                 — difference (in a, not in b)\nprint(a ^ b)       # {1, 2, 5, 6}            — symmetric difference\n\nprint(a.issubset({1, 2, 3, 4, 5}))            # True\nprint({1, 2}.issubset(a))                        # True\nprint(a.isdisjoint({100, 200}))                     # True — no overlap\n\na.add(5)\na.discard(100)      # no error even if 100 is absent (unlike .remove())\n# a.remove(100)      # KeyError: 100  — remove() raises if the element is absent\nprint(a)\n",[29,2027,2028,2053,2079,2083,2098,2113,2127,2142,2146,2177,2194,2215,2219,2228,2240,2245],{"__ignoreMap":27},[32,2029,2030,2033,2035,2037,2039,2041,2043,2045,2047,2049,2051],{"class":34,"line":35},[32,2031,2032],{"class":86},"a ",[32,2034,107],{"class":82},[32,2036,369],{"class":86},[32,2038,291],{"class":136},[32,2040,335],{"class":86},[32,2042,723],{"class":136},[32,2044,335],{"class":86},[32,2046,697],{"class":136},[32,2048,335],{"class":86},[32,2050,761],{"class":136},[32,2052,388],{"class":86},[32,2054,2055,2058,2060,2062,2064,2066,2068,2070,2073,2075,2077],{"class":34,"line":42},[32,2056,2057],{"class":86},"b ",[32,2059,107],{"class":82},[32,2061,369],{"class":86},[32,2063,697],{"class":136},[32,2065,335],{"class":86},[32,2067,761],{"class":136},[32,2069,335],{"class":86},[32,2071,2072],{"class":136},"5",[32,2074,335],{"class":86},[32,2076,1780],{"class":136},[32,2078,388],{"class":86},[32,2080,2081],{"class":34,"line":48},[32,2082,76],{"emptyLinePlaceholder":75},[32,2084,2085,2087,2090,2092,2095],{"class":34,"line":54},[32,2086,281],{"class":136},[32,2088,2089],{"class":86},"(a ",[32,2091,1158],{"class":82},[32,2093,2094],{"class":86}," b)    ",[32,2096,2097],{"class":38},"# {1, 2, 3, 4, 5, 6}   — union\n",[32,2099,2100,2102,2104,2107,2110],{"class":34,"line":60},[32,2101,281],{"class":136},[32,2103,2089],{"class":86},[32,2105,2106],{"class":82},"&",[32,2108,2109],{"class":86}," b)     ",[32,2111,2112],{"class":38},"# {3, 4}                — intersection\n",[32,2114,2115,2117,2119,2121,2124],{"class":34,"line":66},[32,2116,281],{"class":136},[32,2118,2089],{"class":86},[32,2120,1636],{"class":82},[32,2122,2123],{"class":86}," b)      ",[32,2125,2126],{"class":38},"# {1, 2}                 — difference (in a, not in b)\n",[32,2128,2129,2131,2133,2136,2139],{"class":34,"line":72},[32,2130,281],{"class":136},[32,2132,2089],{"class":86},[32,2134,2135],{"class":82},"^",[32,2137,2138],{"class":86}," b)       ",[32,2140,2141],{"class":38},"# {1, 2, 5, 6}            — symmetric difference\n",[32,2143,2144],{"class":34,"line":79},[32,2145,76],{"emptyLinePlaceholder":75},[32,2147,2148,2150,2153,2155,2157,2159,2161,2163,2165,2167,2169,2171,2174],{"class":34,"line":90},[32,2149,281],{"class":136},[32,2151,2152],{"class":86},"(a.issubset({",[32,2154,291],{"class":136},[32,2156,335],{"class":86},[32,2158,723],{"class":136},[32,2160,335],{"class":86},[32,2162,697],{"class":136},[32,2164,335],{"class":86},[32,2166,761],{"class":136},[32,2168,335],{"class":86},[32,2170,2072],{"class":136},[32,2172,2173],{"class":86},"}))            ",[32,2175,2176],{"class":38},"# True\n",[32,2178,2179,2181,2183,2185,2187,2189,2192],{"class":34,"line":95},[32,2180,281],{"class":136},[32,2182,330],{"class":86},[32,2184,291],{"class":136},[32,2186,335],{"class":86},[32,2188,723],{"class":136},[32,2190,2191],{"class":86},"}.issubset(a))                        ",[32,2193,2176],{"class":38},[32,2195,2196,2198,2201,2204,2206,2209,2212],{"class":34,"line":101},[32,2197,281],{"class":136},[32,2199,2200],{"class":86},"(a.isdisjoint({",[32,2202,2203],{"class":136},"100",[32,2205,335],{"class":86},[32,2207,2208],{"class":136},"200",[32,2210,2211],{"class":86},"}))                     ",[32,2213,2214],{"class":38},"# True — no overlap\n",[32,2216,2217],{"class":34,"line":113},[32,2218,76],{"emptyLinePlaceholder":75},[32,2220,2221,2224,2226],{"class":34,"line":124},[32,2222,2223],{"class":86},"a.add(",[32,2225,2072],{"class":136},[32,2227,241],{"class":86},[32,2229,2230,2233,2235,2237],{"class":34,"line":149},[32,2231,2232],{"class":86},"a.discard(",[32,2234,2203],{"class":136},[32,2236,764],{"class":86},[32,2238,2239],{"class":38},"# no error even if 100 is absent (unlike .remove())\n",[32,2241,2242],{"class":34,"line":165},[32,2243,2244],{"class":38},"# a.remove(100)      # KeyError: 100  — remove() raises if the element is absent\n",[32,2246,2247,2249],{"class":34,"line":175},[32,2248,281],{"class":136},[32,2250,2251],{"class":86},"(a)\n",[799,2253,2255],{"id":2254},"sets-deduplicate-automatically-a-common-idiom","Sets deduplicate automatically — a common idiom",[19,2257,2258],{"language":21},[23,2259,2261],{"className":25,"code":2260,"language":21,"meta":27,"style":27},"emails = [\"a@x.com\", \"b@x.com\", \"a@x.com\", \"c@x.com\", \"b@x.com\"]\nunique_emails = list(set(emails))    # order NOT guaranteed to match input!\nprint(sorted(unique_emails))            # sort explicitly if order matters\n\n# To deduplicate WHILE preserving original order, use dict.fromkeys (3.7+)\n# since dicts preserve insertion order but sets do not:\nordered_unique = list(dict.fromkeys(emails))\nprint(ordered_unique)   # ['a@x.com', 'b@x.com', 'c@x.com'] — first-seen order preserved\n",[29,2262,2263,2295,2316,2331,2335,2340,2345,2361],{"__ignoreMap":27},[32,2264,2265,2268,2270,2272,2275,2277,2280,2282,2284,2286,2289,2291,2293],{"class":34,"line":35},[32,2266,2267],{"class":86},"emails ",[32,2269,107],{"class":82},[32,2271,1356],{"class":86},[32,2273,2274],{"class":201},"\"a@x.com\"",[32,2276,335],{"class":86},[32,2278,2279],{"class":201},"\"b@x.com\"",[32,2281,335],{"class":86},[32,2283,2274],{"class":201},[32,2285,335],{"class":86},[32,2287,2288],{"class":201},"\"c@x.com\"",[32,2290,335],{"class":86},[32,2292,2279],{"class":201},[32,2294,1382],{"class":86},[32,2296,2297,2300,2302,2305,2307,2310,2313],{"class":34,"line":42},[32,2298,2299],{"class":86},"unique_emails ",[32,2301,107],{"class":82},[32,2303,2304],{"class":136}," list",[32,2306,140],{"class":86},[32,2308,2309],{"class":136},"set",[32,2311,2312],{"class":86},"(emails))    ",[32,2314,2315],{"class":38},"# order NOT guaranteed to match input!\n",[32,2317,2318,2320,2322,2325,2328],{"class":34,"line":48},[32,2319,281],{"class":136},[32,2321,140],{"class":86},[32,2323,2324],{"class":136},"sorted",[32,2326,2327],{"class":86},"(unique_emails))            ",[32,2329,2330],{"class":38},"# sort explicitly if order matters\n",[32,2332,2333],{"class":34,"line":54},[32,2334,76],{"emptyLinePlaceholder":75},[32,2336,2337],{"class":34,"line":60},[32,2338,2339],{"class":38},"# To deduplicate WHILE preserving original order, use dict.fromkeys (3.7+)\n",[32,2341,2342],{"class":34,"line":66},[32,2343,2344],{"class":38},"# since dicts preserve insertion order but sets do not:\n",[32,2346,2347,2350,2352,2354,2356,2358],{"class":34,"line":72},[32,2348,2349],{"class":86},"ordered_unique ",[32,2351,107],{"class":82},[32,2353,2304],{"class":136},[32,2355,140],{"class":86},[32,2357,1421],{"class":136},[32,2359,2360],{"class":86},".fromkeys(emails))\n",[32,2362,2363,2365,2368],{"class":34,"line":79},[32,2364,281],{"class":136},[32,2366,2367],{"class":86},"(ordered_unique)   ",[32,2369,2370],{"class":38},"# ['a@x.com', 'b@x.com', 'c@x.com'] — first-seen order preserved\n",[14,2372,2374],{"id":2373},"hashability-what-can-be-a-dict-key-or-set-member","Hashability — What Can Be a Dict Key or Set Member",[975,2376,2377,2378,2381,2382,2385,2386,2389,2390,2393],{},"Only ",[978,2379,2380],{},"hashable"," objects can be dict keys or set elements. An object is hashable if it defines ",[29,2383,2384],{},"__hash__"," (and, by convention, ",[29,2387,2388],{},"__eq__"," consistently) and — critically — is ",[978,2391,2392],{},"immutable in the properties used for hashing",".",[19,2395,2396],{"language":21},[23,2397,2399],{"className":25,"code":2398,"language":21,"meta":27,"style":27},"d = {}\nd[(1, 2)] = \"point\"          # tuples of hashable items: OK\nd[\"string\"] = \"ok\"              # strings: OK\nd[42] = \"ok\"                       # ints: OK\nd[frozenset([1, 2])] = \"ok\"           # frozenset: OK (the immutable set variant)\n\n# d[[1, 2]] = \"fails\"      # TypeError: unhashable type: 'list'\n# d[{1, 2}] = \"fails\"        # TypeError: unhashable type: 'set'\n# d[{\"a\": 1}] = \"fails\"        # TypeError: unhashable type: 'dict'\n",[29,2400,2401,2409,2431,2448,2464,2490,2494,2499,2504],{"__ignoreMap":27},[32,2402,2403,2405,2407],{"class":34,"line":35},[32,2404,104],{"class":86},[32,2406,107],{"class":82},[32,2408,110],{"class":86},[32,2410,2411,2414,2416,2418,2420,2423,2425,2428],{"class":34,"line":42},[32,2412,2413],{"class":86},"d[(",[32,2415,291],{"class":136},[32,2417,335],{"class":86},[32,2419,723],{"class":136},[32,2421,2422],{"class":86},")] ",[32,2424,107],{"class":82},[32,2426,2427],{"class":201}," \"point\"",[32,2429,2430],{"class":38},"          # tuples of hashable items: OK\n",[32,2432,2433,2435,2438,2440,2442,2445],{"class":34,"line":48},[32,2434,1050],{"class":86},[32,2436,2437],{"class":201},"\"string\"",[32,2439,1055],{"class":86},[32,2441,107],{"class":82},[32,2443,2444],{"class":201}," \"ok\"",[32,2446,2447],{"class":38},"              # strings: OK\n",[32,2449,2450,2452,2455,2457,2459,2461],{"class":34,"line":54},[32,2451,1050],{"class":86},[32,2453,2454],{"class":136},"42",[32,2456,1055],{"class":86},[32,2458,107],{"class":82},[32,2460,2444],{"class":201},[32,2462,2463],{"class":38},"                       # ints: OK\n",[32,2465,2466,2468,2471,2474,2476,2478,2480,2483,2485,2487],{"class":34,"line":60},[32,2467,1050],{"class":86},[32,2469,2470],{"class":136},"frozenset",[32,2472,2473],{"class":86},"([",[32,2475,291],{"class":136},[32,2477,335],{"class":86},[32,2479,723],{"class":136},[32,2481,2482],{"class":86},"])] ",[32,2484,107],{"class":82},[32,2486,2444],{"class":201},[32,2488,2489],{"class":38},"           # frozenset: OK (the immutable set variant)\n",[32,2491,2492],{"class":34,"line":66},[32,2493,76],{"emptyLinePlaceholder":75},[32,2495,2496],{"class":34,"line":72},[32,2497,2498],{"class":38},"# d[[1, 2]] = \"fails\"      # TypeError: unhashable type: 'list'\n",[32,2500,2501],{"class":34,"line":79},[32,2502,2503],{"class":38},"# d[{1, 2}] = \"fails\"        # TypeError: unhashable type: 'set'\n",[32,2505,2506],{"class":34,"line":90},[32,2507,2508],{"class":38},"# d[{\"a\": 1}] = \"fails\"        # TypeError: unhashable type: 'dict'\n",[975,2510,2511,335,2513,2515,2516,2518,2519,2522],{},[29,2512,939],{},[29,2514,1421],{},", and ",[29,2517,2309],{}," are all unhashable ",[1705,2520,2521],{},"because they're mutable"," — if you could hash a list and then mutate it, its hash would need to change, silently breaking every hash-table invariant (you'd never be able to find it again by its now-stale hash bucket). This is a deliberate, load-bearing design constraint, not an arbitrary limitation.",[14,2524,2526],{"id":2525},"complexity-cheat-sheet","Complexity Cheat Sheet",[2528,2529,2530,2547],"table",{},[2531,2532,2533],"thead",{},[2534,2535,2536,2540,2542,2544],"tr",{},[2537,2538,2539],"th",{},"Operation",[2537,2541,1421],{},[2537,2543,2309],{},[2537,2545,2546],{},"Complexity",[2548,2549,2550,2574,2591,2608],"tbody",{},[2534,2551,2552,2558,2566,2571],{},[2553,2554,2555,2556],"td",{},"Lookup \u002F membership ",[29,2557,133],{},[2553,2559,2560,335,2563],{},[29,2561,2562],{},"d[k]",[29,2564,2565],{},"k in d",[2553,2567,2568],{},[29,2569,2570],{},"x in s",[2553,2572,2573],{},"O(1) average",[2534,2575,2576,2579,2584,2589],{},[2553,2577,2578],{},"Insert",[2553,2580,2581],{},[29,2582,2583],{},"d[k] = v",[2553,2585,2586],{},[29,2587,2588],{},"s.add(x)",[2553,2590,2573],{},[2534,2592,2593,2596,2601,2606],{},[2553,2594,2595],{},"Delete",[2553,2597,2598],{},[29,2599,2600],{},"del d[k]",[2553,2602,2603],{},[29,2604,2605],{},"s.remove(x)",[2553,2607,2573],{},[2534,2609,2610,2613,2618,2623],{},[2553,2611,2612],{},"Iteration",[2553,2614,2615],{},[29,2616,2617],{},"for k in d",[2553,2619,2620],{},[29,2621,2622],{},"for x in s",[2553,2624,2625],{},"O(n)",[975,2627,2628,2629,1708,2632,2635,2636,2639,2640,2643],{},"This O(1) average lookup is ",[1705,2630,2631],{},"why",[29,2633,2634],{},"x in some_set"," or ",[29,2637,2638],{},"x in some_dict"," is dramatically faster than ",[29,2641,2642],{},"x in some_list"," (O(n) linear scan) for large collections — one of the most impactful, easy performance wins in everyday Python code.",[19,2645,2646],{"language":21},[23,2647,2649],{"className":25,"code":2648,"language":21,"meta":27,"style":27},"# SLOW for large data: O(n) per lookup, O(n * m) total\nallowed_ids_list = list(range(100_000))\ndef is_allowed_slow(user_id):\n    return user_id in allowed_ids_list   # linear scan every call\n\n# FAST: O(1) per lookup, O(m) total\nallowed_ids_set = set(range(100_000))\ndef is_allowed_fast(user_id):\n    return user_id in allowed_ids_set    # hash lookup every call\n",[29,2650,2651,2656,2678,2689,2705,2709,2714,2734,2743],{"__ignoreMap":27},[32,2652,2653],{"class":34,"line":35},[32,2654,2655],{"class":38},"# SLOW for large data: O(n) per lookup, O(n * m) total\n",[32,2657,2658,2661,2663,2665,2667,2670,2672,2675],{"class":34,"line":42},[32,2659,2660],{"class":86},"allowed_ids_list ",[32,2662,107],{"class":82},[32,2664,2304],{"class":136},[32,2666,140],{"class":86},[32,2668,2669],{"class":136},"range",[32,2671,140],{"class":86},[32,2673,2674],{"class":136},"100_000",[32,2676,2677],{"class":86},"))\n",[32,2679,2680,2683,2686],{"class":34,"line":48},[32,2681,2682],{"class":82},"def",[32,2684,2685],{"class":444}," is_allowed_slow",[32,2687,2688],{"class":86},"(user_id):\n",[32,2690,2691,2694,2697,2699,2702],{"class":34,"line":54},[32,2692,2693],{"class":82},"    return",[32,2695,2696],{"class":86}," user_id ",[32,2698,133],{"class":82},[32,2700,2701],{"class":86}," allowed_ids_list   ",[32,2703,2704],{"class":38},"# linear scan every call\n",[32,2706,2707],{"class":34,"line":60},[32,2708,76],{"emptyLinePlaceholder":75},[32,2710,2711],{"class":34,"line":66},[32,2712,2713],{"class":38},"# FAST: O(1) per lookup, O(m) total\n",[32,2715,2716,2719,2721,2724,2726,2728,2730,2732],{"class":34,"line":72},[32,2717,2718],{"class":86},"allowed_ids_set ",[32,2720,107],{"class":82},[32,2722,2723],{"class":136}," set",[32,2725,140],{"class":86},[32,2727,2669],{"class":136},[32,2729,140],{"class":86},[32,2731,2674],{"class":136},[32,2733,2677],{"class":86},[32,2735,2736,2738,2741],{"class":34,"line":79},[32,2737,2682],{"class":82},[32,2739,2740],{"class":444}," is_allowed_fast",[32,2742,2688],{"class":86},[32,2744,2745,2747,2749,2751,2754],{"class":34,"line":90},[32,2746,2693],{"class":82},[32,2748,2696],{"class":86},[32,2750,133],{"class":82},[32,2752,2753],{"class":86}," allowed_ids_set    ",[32,2755,2756],{"class":38},"# hash lookup every call\n",[14,2758,2760],{"id":2759},"tips-tricks","💡 Tips & Tricks",[2762,2763,2764,2778,2787,2808,2825],"ul",{},[2765,2766,2767,2773,2774,2777],"li",{},[978,2768,2769,2772],{},[29,2770,2771],{},"dict.fromkeys(iterable)"," deduplicates while preserving first-seen order"," — the idiomatic replacement for ",[29,2775,2776],{},"list(set(x))"," whenever order matters (which is often, e.g., preserving user-input ordering in logs or UI lists).",[2765,2779,2780,2786],{},[978,2781,2782,2785],{},[29,2783,2784],{},"Counter.most_common(n)"," replaces manual sort-by-count boilerplate"," — for \"top N most frequent items\" tasks, this one call replaces building a list of tuples and sorting it yourself.",[2765,2788,2789,2795,2796,2799,2800,2803,2804,2807],{},[978,2790,2791,2794],{},[29,2792,2793],{},"ChainMap"," layers multiple dicts without copying"," — ",[29,2797,2798],{},"collections.ChainMap(overrides, defaults)"," looks up keys in ",[29,2801,2802],{},"overrides"," first, then ",[29,2805,2806],{},"defaults",", without merging them into a new object — ideal for CLI-args-over-config-file-over-defaults precedence chains.",[2765,2809,2810,2816,2817,2820,2821,2824],{},[978,2811,2812,2815],{},[29,2813,2814],{},"dict | other"," (3.9+) is the modern, allocation-clear way to merge two dicts"," — clearer than ",[29,2818,2819],{},"{**a, **b}"," for simple two-dict merges, though ",[29,2822,2823],{},"{**a, **b, \"extra\": 1}"," remains necessary when adding ad hoc keys inline.",[2765,2826,2827,2832,2833,2393],{},[978,2828,2829,2831],{},[29,2830,2470],{}," for hashable, immutable sets"," — when you need a set as a dict key or set member (e.g., memoizing a function that takes an unordered collection of tags), convert with ",[29,2834,2835],{},"frozenset(my_set)",[14,2837,2839],{"id":2838},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2762,2841,2842,2859,2879,2901,2916],{},[2765,2843,2844,2854,2855,2858],{},[978,2845,2846,2848,2849,2848,2851,2853],{},[29,2847,983],{},"\u002F",[29,2850,986],{},[29,2852,989],{}," are live views, not snapshots"," — they reflect the dict's current state even after later mutation, and raise ",[29,2856,2857],{},"RuntimeError: dictionary changed size during iteration"," if you mutate the dict's size while iterating one of these views directly.",[2765,2860,2861,2795,2867,1712,2869,2871,2872,2635,2875,2878],{},[978,2862,2863,2864,2866],{},"Merely reading a missing key on a ",[29,2865,1289],{}," inserts it",[29,2868,1711],{},[29,2870,1289],{}," is not side-effect-free like it is on a regular dict; use ",[29,2873,2874],{},"key in d",[29,2876,2877],{},".get(key)"," (which does NOT trigger the factory) when you want to check without inserting.",[2765,2880,2881,2795,2889,2892,2893,2896,2897,2900],{},[978,2882,2883,2884,1290,2886,2888],{},"Dict\u002Fset key uniqueness depends on ",[29,2885,2388],{},[29,2887,2384],{}," agreeing",[29,2890,2891],{},"1 == 1.0 == True"," are all mutually equal in Python and all hash to the same value, so ",[29,2894,2895],{},"{1, 1.0, True}"," collapses to a set with a single element (whichever was inserted first is retained): ",[29,2898,2899],{},"{1, 1.0, True} == {1}",". This surprises people who expect type to matter for set\u002Fdict-key equality.",[2765,2902,2903,2906,2907,2909,2910,2912,2913,2915],{},[978,2904,2905],{},"Mutating an object after using it as a dict key (if it happens to be a mutable-adjacent custom class) corrupts the hash table"," — if you implement a custom ",[29,2908,2384],{}," based on mutable fields and then mutate those fields, the object becomes unfindable in its own dict\u002Fset (it hashes to a different bucket than where it was originally placed) — this is why hashable custom classes should base ",[29,2911,2384],{}," only on fields that never change after construction (chapter 14 covers implementing ",[29,2914,2384],{}," correctly).",[2765,2917,2918,2921,2922,2925],{},[978,2919,2920],{},"Dict\u002Fset iteration order for sets is insertion-order-like in small cases but is NOT guaranteed by the language at all"," — unlike dicts (where insertion-order preservation is a documented guarantee since 3.7), sets make no ordering guarantee whatsoever; two sets with identical elements inserted in a different order may iterate differently, and this can change between Python versions or even between runs with hash randomization (",[29,2923,2924],{},"PYTHONHASHSEED",") enabled for strings.",[14,2927,2929],{"id":2928},"spot-the-bug","🧠 Spot the Bug",[975,2931,2932,2933,2935],{},"A caching layer uses a ",[29,2934,1289],{}," to track per-user request counts and logs \"new users.\" What's wrong?",[19,2937,2938],{"language":21},[23,2939,2941],{"className":25,"code":2940,"language":21,"meta":27,"style":27},"from collections import defaultdict\n\nrequest_counts = defaultdict(int)\n\ndef log_request(user_id):\n    is_new_user = user_id not in request_counts\n    count = request_counts[user_id]     # bumped below\n    request_counts[user_id] += 1\n    if is_new_user:\n        print(f\"New user seen: {user_id}\")\n\ndef get_active_user_count():\n    return len(request_counts)\n\nlog_request(\"alice\")\nprint(get_active_user_count())\n\n# Somewhere else in the codebase, an unrelated debug check:\nif \"bob\" in request_counts:\n    print(\"bob has made requests\")\nprint(request_counts[\"bob\"])   # a \"harmless\" debug print\nprint(get_active_user_count())\n",[29,2942,2943,2954,2958,2971,2975,2984,3000,3013,3024,3031,3054,3058,3068,3077,3081,3091,3098,3102,3107,3119,3130,3146],{"__ignoreMap":27},[32,2944,2945,2947,2949,2951],{"class":34,"line":35},[32,2946,422],{"class":82},[32,2948,425],{"class":86},[32,2950,83],{"class":82},[32,2952,2953],{"class":86}," defaultdict\n",[32,2955,2956],{"class":34,"line":42},[32,2957,76],{"emptyLinePlaceholder":75},[32,2959,2960,2963,2965,2967,2969],{"class":34,"line":48},[32,2961,2962],{"class":86},"request_counts ",[32,2964,107],{"class":82},[32,2966,1342],{"class":86},[32,2968,469],{"class":136},[32,2970,241],{"class":86},[32,2972,2973],{"class":34,"line":54},[32,2974,76],{"emptyLinePlaceholder":75},[32,2976,2977,2979,2982],{"class":34,"line":60},[32,2978,2682],{"class":82},[32,2980,2981],{"class":444}," log_request",[32,2983,2688],{"class":86},[32,2985,2986,2989,2991,2993,2995,2997],{"class":34,"line":66},[32,2987,2988],{"class":86},"    is_new_user ",[32,2990,107],{"class":82},[32,2992,2696],{"class":86},[32,2994,532],{"class":82},[32,2996,535],{"class":82},[32,2998,2999],{"class":86}," request_counts\n",[32,3001,3002,3005,3007,3010],{"class":34,"line":72},[32,3003,3004],{"class":86},"    count ",[32,3006,107],{"class":82},[32,3008,3009],{"class":86}," request_counts[user_id]     ",[32,3011,3012],{"class":38},"# bumped below\n",[32,3014,3015,3018,3021],{"class":34,"line":79},[32,3016,3017],{"class":86},"    request_counts[user_id] ",[32,3019,3020],{"class":82},"+=",[32,3022,3023],{"class":136}," 1\n",[32,3025,3026,3028],{"class":34,"line":90},[32,3027,178],{"class":82},[32,3029,3030],{"class":86}," is_new_user:\n",[32,3032,3033,3035,3037,3039,3042,3044,3047,3049,3052],{"class":34,"line":95},[32,3034,193],{"class":136},[32,3036,140],{"class":86},[32,3038,198],{"class":82},[32,3040,3041],{"class":201},"\"New user seen: ",[32,3043,220],{"class":136},[32,3045,3046],{"class":86},"user_id",[32,3048,214],{"class":136},[32,3050,3051],{"class":201},"\"",[32,3053,241],{"class":86},[32,3055,3056],{"class":34,"line":101},[32,3057,76],{"emptyLinePlaceholder":75},[32,3059,3060,3062,3065],{"class":34,"line":113},[32,3061,2682],{"class":82},[32,3063,3064],{"class":444}," get_active_user_count",[32,3066,3067],{"class":86},"():\n",[32,3069,3070,3072,3074],{"class":34,"line":124},[32,3071,2693],{"class":82},[32,3073,639],{"class":136},[32,3075,3076],{"class":86},"(request_counts)\n",[32,3078,3079],{"class":34,"line":149},[32,3080,76],{"emptyLinePlaceholder":75},[32,3082,3083,3086,3089],{"class":34,"line":165},[32,3084,3085],{"class":86},"log_request(",[32,3087,3088],{"class":201},"\"alice\"",[32,3090,241],{"class":86},[32,3092,3093,3095],{"class":34,"line":175},[32,3094,281],{"class":136},[32,3096,3097],{"class":86},"(get_active_user_count())\n",[32,3099,3100],{"class":34,"line":190},[32,3101,76],{"emptyLinePlaceholder":75},[32,3103,3104],{"class":34,"line":244},[32,3105,3106],{"class":38},"# Somewhere else in the codebase, an unrelated debug check:\n",[32,3108,3109,3111,3114,3116],{"class":34,"line":255},[32,3110,1935],{"class":82},[32,3112,3113],{"class":201}," \"bob\"",[32,3115,535],{"class":82},[32,3117,3118],{"class":86}," request_counts:\n",[32,3120,3121,3123,3125,3128],{"class":34,"line":261},[32,3122,871],{"class":136},[32,3124,140],{"class":86},[32,3126,3127],{"class":201},"\"bob has made requests\"",[32,3129,241],{"class":86},[32,3131,3132,3134,3137,3140,3143],{"class":34,"line":266},[32,3133,281],{"class":136},[32,3135,3136],{"class":86},"(request_counts[",[32,3138,3139],{"class":201},"\"bob\"",[32,3141,3142],{"class":86},"])   ",[32,3144,3145],{"class":38},"# a \"harmless\" debug print\n",[32,3147,3148,3150],{"class":34,"line":272},[32,3149,281],{"class":136},[32,3151,3097],{"class":86},[3153,3154,3155,3159,3194,3205],"details",{},[3156,3157,3158],"summary",{},"Answer",[975,3160,3161,3162,3165,3166,3168,3169,3171,3172,3174,3175,3178,3179,3182,3183,3186,3187,3189,3190,3193],{},"After the debug print, ",[29,3163,3164],{},"get_active_user_count()"," returns ",[29,3167,723],{},", not ",[29,3170,291],{}," — even though ",[29,3173,3139],{}," never made a real request. ",[29,3176,3177],{},"print(request_counts[\"bob\"])"," reads a missing key on a ",[29,3180,3181],{},"defaultdict(int)",", which silently inserts ",[29,3184,3185],{},"\"bob\": 0"," as a side effect of the read. The subsequent ",[29,3188,3164],{}," (which just does ",[29,3191,3192],{},"len(request_counts)",") now counts bob as an \"active user\" purely because someone printed his count for debugging.",[975,3195,3196,3197,3200,3201,3204],{},"The fix: use ",[29,3198,3199],{},"request_counts.get(user_id, 0)"," for read-only inspection (never triggers the factory), and reserve ",[29,3202,3203],{},"request_counts[user_id]"," for code paths that genuinely intend to create-or-update an entry.",[975,3206,3207,217,3210,3212,3213,3215,3216,3218,3219,3222],{},[978,3208,3209],{},"The lesson",[29,3211,1289],{}," trades ",[29,3214,1725],{}," safety for a subtler hazard — reads are not side-effect-free, so ",[29,3217,133],{},"-checks and ",[29,3220,3221],{},"len()"," after speculative\u002Fdebug reads can silently include entries nobody meant to create.",[14,3224,3226],{"id":3225},"key-takeaways","Key Takeaways",[2762,3228,3229,3239,3255,3268,3271],{},[2765,3230,3231,3232,2848,3234,2848,3236,3238],{},"Dicts preserve insertion order (guaranteed since 3.7); ",[29,3233,983],{},[29,3235,986],{},[29,3237,989],{}," return live views, not static lists.",[2765,3240,3241,1290,3244,3247,3248,3250,3251,3254],{},[29,3242,3243],{},".get()",[29,3245,3246],{},".setdefault()"," avoid ",[29,3249,1725],{}," for reads and conditional inserts respectively; prefer them over manual ",[29,3252,3253],{},"if key in d"," boilerplate.",[2765,3256,3257,1290,3259,3261,3262,3264,3265,3267],{},[29,3258,1289],{},[29,3260,1293],{}," from ",[29,3263,1299],{}," eliminate common manual-initialization boilerplate — but remember that reading a missing key on a ",[29,3266,1289],{}," inserts it.",[2765,3269,3270],{},"Only immutable-by-contract, hashable objects (numbers, strings, tuples-of-hashables, frozensets) can be dict keys or set members — this is a deliberate consequence of how hash tables work, not an arbitrary restriction.",[2765,3272,3273,2848,3275,3277,3278,3280],{},[29,3274,2634],{},[29,3276,2638],{}," is O(1) average vs. O(n) for ",[29,3279,2642],{}," — converting a large membership-checked list to a set is one of the highest-leverage, lowest-effort performance fixes in everyday Python.",[3282,3283,3284],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}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 .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}",{"title":27,"searchDepth":42,"depth":42,"links":3286},[3287,3290,3291,3296,3297,3300,3301,3302,3303,3304,3305],{"id":16,"depth":42,"text":17,"children":3288},[3289],{"id":801,"depth":48,"text":802},{"id":1082,"depth":42,"text":1083},{"id":1286,"depth":42,"text":3292,"children":3293},"defaultdict and Counter",[3294],{"id":1644,"depth":48,"text":3295},"The defaultdict factory-function gotcha",{"id":1737,"depth":42,"text":1738},{"id":2019,"depth":42,"text":2020,"children":3298},[3299],{"id":2254,"depth":48,"text":2255},{"id":2373,"depth":42,"text":2374},{"id":2525,"depth":42,"text":2526},{"id":2759,"depth":42,"text":2760},{"id":2838,"depth":42,"text":2839},{"id":2928,"depth":42,"text":2929},{"id":3225,"depth":42,"text":3226},"md",{},"\u002Fpython\u002F08-dictionaries-and-sets",{"title":5,"description":27},"python\u002F08-dictionaries-and-sets","2KX9UO_Np6GnbIYA82SywnA2GekJlRyGeZSp74Y4td8",1789924651409]