[{"data":1,"prerenderedAt":252},["ShallowReactive",2],{"tag-labels":3,"site-header":4,"article-python-tuples-en":69},{},{"featuredPost":5,"navigations":26},{"id":6,"title":7,"title_en":8,"slug":9,"excerpt":10,"excerpt_en":8,"has_translation":11,"published_at":12,"reading_time":13,"hidden_from_listing":11,"tags":14,"thumbnail_image":8,"og_image":19,"series":20,"authors":25},110,"Ketika Pilih Framework Cuma Biar Kelihatan Beda",null,"ketika-pilih-framework-cuma-biar-kelihatan-beda","Terakhir kali kamu milih framework atau library baru, itu karena masalahmu butuh alat itu, atau karena alatnya kedengaran keren dan belum banyak yang pakai? Pertanyaan ini nggak enak dijawab. Soalnya keputusan teknologi sering diambil dengan alasan yang nggak pernah ditulis di dokumen teknis mana pun.",false,"2026-10-06T15:25:21.000Z",5,[15,16,17,18],"karier","framework","opini","pengalaman","\u002Fog\u002Fketika-pilih-framework-cuma-biar-kelihatan-beda.png",{"id":21,"title":22,"title_en":23,"slug":24},9,"Artikel","Articles","all",[],[27,43,64],{"collection":28,"item":29},"series",{"__typename":28,"title":22,"title_en":23,"slug":24,"children_series":30},[31,35,39],{"title":32,"title_en":33,"slug":34},"Kecerdasan Artifisial","Artificial Intelligence","kecerdasan-artifisial",{"title":36,"title_en":37,"slug":38},"Konsep Dasar Pemrograman","Programming Fundamentals","konsep-dasar-pemrograman",{"title":40,"title_en":41,"slug":42},"Algoritma dan Struktur Data","Algorithms and Data Structures","algoritma-struktur-data",{"collection":28,"item":44},{"__typename":28,"title":45,"title_en":45,"slug":46,"children_series":47},"Tutorial","tutorial",[48,52,56,60],{"title":49,"title_en":50,"slug":51},"Belajar Python","Learning Python","belajar-python",{"title":53,"title_en":54,"slug":55},"Belajar Golang","Learning Go","belajar-golang",{"title":57,"title_en":58,"slug":59},"Belajar Java","Learning Java","belajar-java",{"title":61,"title_en":62,"slug":63},"Belajar Pascal","Learning Pascal","belajar-pascal",{"collection":28,"item":65},{"__typename":28,"title":66,"title_en":66,"slug":67,"children_series":68},"Lab","lab",[],{"article":70,"renderedBody":163,"renderedTakeaway":164,"latestArticles":165,"toc":235},{"id":71,"title":72,"title_en":8,"slug":73,"excerpt":74,"excerpt_en":8,"has_translation":11,"published_at":75,"reading_time":76,"hidden_from_listing":11,"tags":77,"thumbnail_image":8,"og_image":80,"series":81,"authors":155,"body_locale":158,"available_locales":159,"body":161,"takeway":162,"prerequisite":8},132,"Python Tuples: Why All Three Points Are the Same Point","python-tuples","Three points walk into a loop and come out identical. The list was never copied three times; the name was. A tuple makes that bug impossible.","2026-10-28T12:00:00.000Z",6,[78,79],"python","tuple","\u002Fog\u002Fpython-tuples.png",{"id":82,"title":83,"title_en":84,"slug":85,"description":86,"description_en":87,"articles":88,"children_series":124,"parent_series":125},30,"Koleksi dan String","Collections and Strings","python-collections","Dictionary, set, tuple, dan cara mengolah string. Tipe data yang baru kepakai begitu program berhenti menyimpan satu nilai saja.","Dictionaries, sets, tuples, and the string methods that do the boring parts. The types you need once a program stops holding a single value.",[89,106,119],{"id":90,"title":91,"title_en":8,"slug":92,"excerpt":93,"excerpt_en":8,"has_translation":11,"published_at":94,"reading_time":76,"hidden_from_listing":11,"tags":95,"thumbnail_image":8,"og_image":97,"series":98,"authors":99},130,"Python Dictionaries: the Key That Isn't There","python-dictionary","A word counter dies the first time it meets a word twice. The fix is one line; what takes longer is knowing which of a dict's three lookups to reach for.","2026-10-28T10:00:00.000Z",[78,96],"dictionary","\u002Fog\u002Fpython-dictionary.png",{"id":82,"title":83,"title_en":84,"slug":85},[100],{"authors_id":101},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},1,"Daffa Izzuddin","izzudd","Writer",{"id":107,"title":108,"title_en":8,"slug":109,"excerpt":110,"excerpt_en":8,"has_translation":11,"published_at":111,"reading_time":76,"hidden_from_listing":11,"tags":112,"thumbnail_image":8,"og_image":114,"series":115,"authors":116},131,"Python Sets: the Duplicate That Keeps Coming Back","python-sets","A de-duplication loop that works on clean data leaves four tags where there should be two. The bug is case, and the fix is a `set`.","2026-10-28T11:00:00.000Z",[78,113],"set","\u002Fog\u002Fpython-sets.png",{"id":82,"title":83,"title_en":84,"slug":85},[117],{"authors_id":118},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},{"id":71,"title":72,"title_en":8,"slug":73,"excerpt":74,"excerpt_en":8,"has_translation":11,"published_at":75,"reading_time":76,"hidden_from_listing":11,"tags":77,"thumbnail_image":8,"og_image":80,"series":120,"authors":121},{"id":82,"title":83,"title_en":84,"slug":85},[122],{"authors_id":123},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},[],{"id":126,"title":49,"title_en":50,"slug":51,"parent_series":127,"children_series":128},10,{"id":102,"title":45,"title_en":45,"slug":46},[129,134,139,144,149,154],{"id":130,"title":131,"title_en":132,"slug":133,"cover_image":8},16,"Berkenalan dengan Bahasa Python","Getting Started with Python","python-intro",{"id":135,"title":136,"title_en":137,"slug":138,"cover_image":8},17,"Variabel, Tipe Data, dan Operasi","Variables, Types, and Operations","python-variabel-tipe-data",{"id":140,"title":141,"title_en":142,"slug":143,"cover_image":8},18,"Menggunakan Script Python","Working with Python Scripts","python-pemrograman-dengan-script",{"id":145,"title":146,"title_en":147,"slug":148,"cover_image":8},19,"Struktur Kontrol","Control Structures","python-struktur-kontrol",{"id":150,"title":151,"title_en":152,"slug":153,"cover_image":8},20,"Pemrograman Fungsional dengan Python","Functional Programming with Python","python-pemrograman-fungsional",{"id":82,"title":83,"title_en":84,"slug":85,"cover_image":8},[156],{"authors_id":157},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},"en",[160],"id","\nThree points, one loop, and the printed output is the same point three times. The loop looks like it does what it says: it shifts each point by its index, so the points should end up at `(0, 0)`, `(1, 0)`, `(2, 0)`.\n\nThey end up at `(2, 0)`, `(2, 0)`, `(2, 0)`.\n\n## Two files, one command\n\nWrite the program, paste the checker, run it until it goes green. No repository, no Docker, `python3` only.\n\nCreate `shift.py`:\n\n```python\n# shift.py\nstart = [0, 0]\npoints = [start] * 3\n\nfor step, point in enumerate(points):\n    point[0] = step\n\nfor point in points:\n    print(f\"({point[0]}, {point[1]})\")\n```\n\nThen `check_shift.py`:\n\n```python\n# check_shift.py\nimport subprocess\nimport sys\n\nEXPECTED = [\"(0, 0)\", \"(1, 0)\", \"(2, 0)\"]\n\n\ndef report(results):\n    for label, passed, detail in results:\n        mark = \"PASS\" if passed else \"FAIL\"\n        note = f\"  \u003C- {detail}\" if detail and not passed else \"\"\n        print(f\"{mark}  {label}{note}\")\n    passed = [ok for _, ok, _ in results].count(True)\n    print(f\"\\n{passed} of {len(results)} checks passed\")\n\n\ndef main():\n    run = subprocess.run([sys.executable, \"shift.py\"], text=True, capture_output=True)\n    crashed = run.returncode != 0\n    last_error = run.stderr.strip().splitlines()[-1] if run.stderr.strip() else \"\"\n\n    results = [(\"the script runs without crashing\", not crashed, last_error)]\n    if crashed:\n        report(results)\n        return 1\n\n    printed = [line.strip() for line in run.stdout.splitlines() if line.strip()]\n\n    results.append((\"prints three points\", len(printed) == 3, f\"got {len(printed)}: {printed}\"))\n    results.append((\"no point is printed twice\", len(set(printed)) == len(printed), str(printed)))\n    results.append((\"the points are (0, 0), (1, 0), (2, 0)\", printed == EXPECTED, str(printed)))\n\n    report(results)\n    return 0 if all(ok for _, ok, _ in results) else 1\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n```\n\n```\n$ python3 check_shift.py\nPASS  the script runs without crashing\nPASS  prints three points\nFAIL  no point is printed twice  \u003C- ['(2, 0)', '(2, 0)', '(2, 0)']\nFAIL  the points are (0, 0), (1, 0), (2, 0)  \u003C- ['(2, 0)', '(2, 0)', '(2, 0)']\n\n2 of 4 checks passed\n```\n\n## `* 3` copies the name, not the list\n\n`[start] * 3` builds a list with three entries. Each entry is `start` — not a copy of `[0, 0]`, but the same list, three times. There is one list in memory and three labels pointing at it, like three keys to one locker.\n\nSo `point[0] = step` on the second pass does not update \"the second point\". It updates the only list there is, and the first and third entries change with it. The last write wins, which is why every line says `(2, 0)`.\n\nThis is what people mean when they say a list is *mutable* and that assignment does not copy. Two consequences worth remembering:\n\n- To get three independent lists, you have to create three: `[[0, 0] for _ in range(3)]`.\n- A checker that only looks at the first line would have passed. Printing every entry is what made the bug visible.\n\nSpotting it in your own code is mostly about suspicion at the right moment. Whenever you build a list by multiplying something, ask what that something is. `[0] * 3` is fine, because `0` is a number and a number cannot be edited. `[start] * 3` is not, because `start` is a container, and every entry is that one container rather than a copy of it.\n\n## A tuple is the same idea with the door welded shut\n\nA tuple is an ordered collection you cannot change after it is created. Round brackets instead of square:\n\n```python\nstart = (0, 0)\n```\n\n`start[0] = 1` now raises `TypeError`. You cannot break it by accident, so you cannot share it by accident either — three entries pointing at one tuple is not a bug, because nothing can mutate it.\n\nThe cost is that \"shifting a point\" becomes \"building a new point\" instead of editing the old one:\n\n```python\n# shift.py\nstart = (0, 0)\npoints = [start] * 3\n\npoints = [(point[0] + step, point[1]) for step, point in enumerate(points)]\n\nfor point in points:\n    print(f\"({point[0]}, {point[1]})\")\n```\n\n```\n$ python3 check_shift.py\nPASS  the script runs without crashing\nPASS  prints three points\nPASS  no point is printed twice\nPASS  the points are (0, 0), (1, 0), (2, 0)\n\n4 of 4 checks passed\n```\n\nThe comprehension builds a new list of new tuples; nothing is edited in place, so nothing is shared. `enumerate` gives you the step, the arithmetic produces `(0, 0)`, `(1, 0)`, `(2, 0)`, and the old list is simply replaced.\n\n## Where tuples earn their place\n\nA tuple is the right container for a record that describes one thing: a coordinate, an RGB colour, a width and a height, a row you read from a file and never edit. Those values belong together, their order is part of their meaning, and editing one of them in place is not something you should be able to do.\n\nThe most common case is returning more than one value. When a function hands back a minimum and a maximum, it hands back a tuple, and `low, high = min_and_max(numbers)` is unpacking. You have been doing this since the first `return` you wrote with a comma in it, without needing the name for it.\n\n```python\npoint = (3, 4)\nx, y = point\nprint(x + y)\n```\n\nThat single line also explains the next property. A tuple is hashable, so it can be a dict key: a grid lookup as `grid[(3, 4)]` is unremarkable. The list version, `grid[[3, 4]]`, raises `TypeError` — the sentence from the previous article cashing out. Anything that can be put in a set or used as a key has to be unchangeable, because a mutable key would move after the container had already filed it.\n\nThe last use is deliberately boring: passing a tuple tells the next person, and the interpreter, that this value is not up for editing. It is not a performance trick and it will not make the code faster. It removes a category of bug, which is worth more.\n\nSo: **a tuple is a record that should not change; a list is a collection you intend to change.** When you need to \"modify\" a tuple, you build a new one. Half the time that turns out to be a clearer description of what you meant anyway, and the other half is a hint that the value belonged in a dict.\n\n## Before the next article\n\nReplace `[start] * 3` with `[[0, 0] for _ in range(3)]` and keep everything else from the broken version. It passes too. Two fixes, one bug — and only one of them stops the *next* person from editing a shared point.\n","- `[item] * 3` repeats the reference, not the value, so all three entries point at one object.\n- Mutating any of them mutates all of them; the bug is invisible until you print every entry.\n- A tuple cannot be changed, so sharing one between entries cannot go wrong — that is its main job.\n- `x, y = point` unpacks, and a tuple can be a dict key because it is hashable.\n- Reach for a tuple for fixed records (a coordinate, an RGB colour, a row you never edit) and a list for anything you intend to grow or edit.","\u003Cp>Three points, one loop, and the printed output is the same point three times. The loop looks like it does what it says: it shifts each point by its index, so the points should end up at \u003Ccode>(0, 0)\u003C\u002Fcode>, \u003Ccode>(1, 0)\u003C\u002Fcode>, \u003Ccode>(2, 0)\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>They end up at \u003Ccode>(2, 0)\u003C\u002Fcode>, \u003Ccode>(2, 0)\u003C\u002Fcode>, \u003Ccode>(2, 0)\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"two-files-one-command\">Two files, one command\u003C\u002Fh2>\n\u003Cp>Write the program, paste the checker, run it until it goes green. No repository, no Docker, \u003Ccode>python3\u003C\u002Fcode> only.\u003C\u002Fp>\n\u003Cp>Create \u003Ccode>shift.py\u003C\u002Fcode>:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">PYTHON\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"%23%20shift.py%0Astart%20%3D%20%5B0%2C%200%5D%0Apoints%20%3D%20%5Bstart%5D%20*%203%0A%0Afor%20step%2C%20point%20in%20enumerate(points)%3A%0A%20%20%20%20point%5B0%5D%20%3D%20step%0A%0Afor%20point%20in%20points%3A%0A%20%20%20%20print(f%22(%7Bpoint%5B0%5D%7D%2C%20%7Bpoint%5B1%5D%7D)%22)\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># shift.py\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">start \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">points \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [start] \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">*\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 3\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> step, point \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> enumerate\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(points):\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    point[\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">] \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> step\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> point \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> points:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"(\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">point[\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">]\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">point[\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">1\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">]\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">)\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Then \u003Ccode>check_shift.py\u003C\u002Fcode>:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">PYTHON\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"%23%20check_shift.py%0Aimport%20subprocess%0Aimport%20sys%0A%0AEXPECTED%20%3D%20%5B%22(0%2C%200)%22%2C%20%22(1%2C%200)%22%2C%20%22(2%2C%200)%22%5D%0A%0A%0Adef%20report(results)%3A%0A%20%20%20%20for%20label%2C%20passed%2C%20detail%20in%20results%3A%0A%20%20%20%20%20%20%20%20mark%20%3D%20%22PASS%22%20if%20passed%20else%20%22FAIL%22%0A%20%20%20%20%20%20%20%20note%20%3D%20f%22%20%20%3C-%20%7Bdetail%7D%22%20if%20detail%20and%20not%20passed%20else%20%22%22%0A%20%20%20%20%20%20%20%20print(f%22%7Bmark%7D%20%20%7Blabel%7D%7Bnote%7D%22)%0A%20%20%20%20passed%20%3D%20%5Bok%20for%20_%2C%20ok%2C%20_%20in%20results%5D.count(True)%0A%20%20%20%20print(f%22%5Cn%7Bpassed%7D%20of%20%7Blen(results)%7D%20checks%20passed%22)%0A%0A%0Adef%20main()%3A%0A%20%20%20%20run%20%3D%20subprocess.run(%5Bsys.executable%2C%20%22shift.py%22%5D%2C%20text%3DTrue%2C%20capture_output%3DTrue)%0A%20%20%20%20crashed%20%3D%20run.returncode%20!%3D%200%0A%20%20%20%20last_error%20%3D%20run.stderr.strip().splitlines()%5B-1%5D%20if%20run.stderr.strip()%20else%20%22%22%0A%0A%20%20%20%20results%20%3D%20%5B(%22the%20script%20runs%20without%20crashing%22%2C%20not%20crashed%2C%20last_error)%5D%0A%20%20%20%20if%20crashed%3A%0A%20%20%20%20%20%20%20%20report(results)%0A%20%20%20%20%20%20%20%20return%201%0A%0A%20%20%20%20printed%20%3D%20%5Bline.strip()%20for%20line%20in%20run.stdout.splitlines()%20if%20line.strip()%5D%0A%0A%20%20%20%20results.append((%22prints%20three%20points%22%2C%20len(printed)%20%3D%3D%203%2C%20f%22got%20%7Blen(printed)%7D%3A%20%7Bprinted%7D%22))%0A%20%20%20%20results.append((%22no%20point%20is%20printed%20twice%22%2C%20len(set(printed))%20%3D%3D%20len(printed)%2C%20str(printed)))%0A%20%20%20%20results.append((%22the%20points%20are%20(0%2C%200)%2C%20(1%2C%200)%2C%20(2%2C%200)%22%2C%20printed%20%3D%3D%20EXPECTED%2C%20str(printed)))%0A%0A%20%20%20%20report(results)%0A%20%20%20%20return%200%20if%20all(ok%20for%20_%2C%20ok%2C%20_%20in%20results)%20else%201%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20sys.exit(main())\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># check_shift.py\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> subprocess\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> sys\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">EXPECTED\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"(0, 0)\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"(1, 0)\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"(2, 0)\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C\u002Fspan>\u003Cspan style=\"color:#B392F0\"> report\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(results):\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> label, passed, detail \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> results:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        mark \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"PASS\"\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> passed \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"FAIL\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        note \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"  &#x3C;- \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">detail\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> detail \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">and\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> not\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> passed \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">        print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">mark\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">  {\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">label\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">note\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    passed \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [ok \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> _, ok, _ \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> results].count(\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">True\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">\\n{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">passed\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> of \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{len\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(results)\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> checks passed\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C\u002Fspan>\u003Cspan style=\"color:#B392F0\"> main\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">():\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    run \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> subprocess.run([sys.executable, \u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"shift.py\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">], \u003C\u002Fspan>\u003Cspan style=\"color:#FFAB70\">text\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">True\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FFAB70\">capture_output\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">True\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    crashed \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> run.returncode \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">!=\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    last_error \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> run.stderr.strip().splitlines()[\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">-\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">1\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">] \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">if\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> run.stderr.strip() \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    results \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [(\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"the script runs without crashing\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">not\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> crashed, last_error)]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    if\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> crashed:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        report(results)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">        return\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 1\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    printed \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [line.strip() \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> line \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> run.stdout.splitlines() \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">if\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> line.strip()]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    results.append((\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"prints three points\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">len\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(printed) \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 3\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"got \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{len\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(printed)\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">: \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">printed\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    results.append((\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"no point is printed twice\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">len\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">set\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(printed)) \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> len\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(printed), \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">str\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(printed)))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    results.append((\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"the points are (0, 0), (1, 0), (2, 0)\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, printed \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> EXPECTED\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">str\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(printed)))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    report(results)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 0\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> all\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(ok \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> _, ok, _ \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> results) \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 1\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">if\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> __name__\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> ==\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"__main__\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    sys.exit(main())\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">TEXT\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"%24%20python3%20check_shift.py%0APASS%20%20the%20script%20runs%20without%20crashing%0APASS%20%20prints%20three%20points%0AFAIL%20%20no%20point%20is%20printed%20twice%20%20%3C-%20%5B'(2%2C%200)'%2C%20'(2%2C%200)'%2C%20'(2%2C%200)'%5D%0AFAIL%20%20the%20points%20are%20(0%2C%200)%2C%20(1%2C%200)%2C%20(2%2C%200)%20%20%3C-%20%5B'(2%2C%200)'%2C%20'(2%2C%200)'%2C%20'(2%2C%200)'%5D%0A%0A2%20of%204%20checks%20passed\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\">\u003Ccode>$ python3 check_shift.py\nPASS  the script runs without crashing\nPASS  prints three points\nFAIL  no point is printed twice  &lt;- ['(2, 0)', '(2, 0)', '(2, 0)']\nFAIL  the points are (0, 0), (1, 0), (2, 0)  &lt;- ['(2, 0)', '(2, 0)', '(2, 0)']\n\n2 of 4 checks passed\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Ch2 id=\"3-copies-the-name-not-the-list\">\u003Ccode>* 3\u003C\u002Fcode> copies the name, not the list\u003C\u002Fh2>\n\u003Cp>\u003Ccode>[start] * 3\u003C\u002Fcode> builds a list with three entries. Each entry is \u003Ccode>start\u003C\u002Fcode> — not a copy of \u003Ccode>[0, 0]\u003C\u002Fcode>, but the same list, three times. There is one list in memory and three labels pointing at it, like three keys to one locker.\u003C\u002Fp>\n\u003Cp>So \u003Ccode>point[0] = step\u003C\u002Fcode> on the second pass does not update &quot;the second point&quot;. It updates the only list there is, and the first and third entries change with it. The last write wins, which is why every line says \u003Ccode>(2, 0)\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>This is what people mean when they say a list is \u003Cem>mutable\u003C\u002Fem> and that assignment does not copy. Two consequences worth remembering:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>To get three independent lists, you have to create three: \u003Ccode>[[0, 0] for _ in range(3)]\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>A checker that only looks at the first line would have passed. Printing every entry is what made the bug visible.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Spotting it in your own code is mostly about suspicion at the right moment. Whenever you build a list by multiplying something, ask what that something is. \u003Ccode>[0] * 3\u003C\u002Fcode> is fine, because \u003Ccode>0\u003C\u002Fcode> is a number and a number cannot be edited. \u003Ccode>[start] * 3\u003C\u002Fcode> is not, because \u003Ccode>start\u003C\u002Fcode> is a container, and every entry is that one container rather than a copy of it.\u003C\u002Fp>\n\u003Ch2 id=\"a-tuple-is-the-same-idea-with-the-door-welded-shut\">A tuple is the same idea with the door welded shut\u003C\u002Fh2>\n\u003Cp>A tuple is an ordered collection you cannot change after it is created. Round brackets instead of square:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">PYTHON\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"start%20%3D%20(0%2C%200)\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">start \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>\u003Ccode>start[0] = 1\u003C\u002Fcode> now raises \u003Ccode>TypeError\u003C\u002Fcode>. You cannot break it by accident, so you cannot share it by accident either — three entries pointing at one tuple is not a bug, because nothing can mutate it.\u003C\u002Fp>\n\u003Cp>The cost is that &quot;shifting a point&quot; becomes &quot;building a new point&quot; instead of editing the old one:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">PYTHON\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"%23%20shift.py%0Astart%20%3D%20(0%2C%200)%0Apoints%20%3D%20%5Bstart%5D%20*%203%0A%0Apoints%20%3D%20%5B(point%5B0%5D%20%2B%20step%2C%20point%5B1%5D)%20for%20step%2C%20point%20in%20enumerate(points)%5D%0A%0Afor%20point%20in%20points%3A%0A%20%20%20%20print(f%22(%7Bpoint%5B0%5D%7D%2C%20%7Bpoint%5B1%5D%7D)%22)\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># shift.py\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">start \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">points \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [start] \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">*\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 3\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">points \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [(point[\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">] \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> step, point[\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">1\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">]) \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> step, point \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> enumerate\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(points)]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> point \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> points:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"(\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">point[\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">]\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">point[\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">1\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">]\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">)\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">TEXT\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"%24%20python3%20check_shift.py%0APASS%20%20the%20script%20runs%20without%20crashing%0APASS%20%20prints%20three%20points%0APASS%20%20no%20point%20is%20printed%20twice%0APASS%20%20the%20points%20are%20(0%2C%200)%2C%20(1%2C%200)%2C%20(2%2C%200)%0A%0A4%20of%204%20checks%20passed\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\">\u003Ccode>$ python3 check_shift.py\nPASS  the script runs without crashing\nPASS  prints three points\nPASS  no point is printed twice\nPASS  the points are (0, 0), (1, 0), (2, 0)\n\n4 of 4 checks passed\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>The comprehension builds a new list of new tuples; nothing is edited in place, so nothing is shared. \u003Ccode>enumerate\u003C\u002Fcode> gives you the step, the arithmetic produces \u003Ccode>(0, 0)\u003C\u002Fcode>, \u003Ccode>(1, 0)\u003C\u002Fcode>, \u003Ccode>(2, 0)\u003C\u002Fcode>, and the old list is simply replaced.\u003C\u002Fp>\n\u003Ch2 id=\"where-tuples-earn-their-place\">Where tuples earn their place\u003C\u002Fh2>\n\u003Cp>A tuple is the right container for a record that describes one thing: a coordinate, an RGB colour, a width and a height, a row you read from a file and never edit. Those values belong together, their order is part of their meaning, and editing one of them in place is not something you should be able to do.\u003C\u002Fp>\n\u003Cp>The most common case is returning more than one value. When a function hands back a minimum and a maximum, it hands back a tuple, and \u003Ccode>low, high = min_and_max(numbers)\u003C\u002Fcode> is unpacking. You have been doing this since the first \u003Ccode>return\u003C\u002Fcode> you wrote with a comma in it, without needing the name for it.\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">PYTHON\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"point%20%3D%20(3%2C%204)%0Ax%2C%20y%20%3D%20point%0Aprint(x%20%2B%20y)\" title=\"Salin kode\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Copy\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">point \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">3\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">4\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">x, y \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> point\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(x \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> y)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>That single line also explains the next property. A tuple is hashable, so it can be a dict key: a grid lookup as \u003Ccode>grid[(3, 4)]\u003C\u002Fcode> is unremarkable. The list version, \u003Ccode>grid[[3, 4]]\u003C\u002Fcode>, raises \u003Ccode>TypeError\u003C\u002Fcode> — the sentence from the previous article cashing out. Anything that can be put in a set or used as a key has to be unchangeable, because a mutable key would move after the container had already filed it.\u003C\u002Fp>\n\u003Cp>The last use is deliberately boring: passing a tuple tells the next person, and the interpreter, that this value is not up for editing. It is not a performance trick and it will not make the code faster. It removes a category of bug, which is worth more.\u003C\u002Fp>\n\u003Cp>So: \u003Cstrong>a tuple is a record that should not change; a list is a collection you intend to change.\u003C\u002Fstrong> When you need to &quot;modify&quot; a tuple, you build a new one. Half the time that turns out to be a clearer description of what you meant anyway, and the other half is a hint that the value belonged in a dict.\u003C\u002Fp>\n\u003Ch2 id=\"before-the-next-article\">Before the next article\u003C\u002Fh2>\n\u003Cp>Replace \u003Ccode>[start] * 3\u003C\u002Fcode> with \u003Ccode>[[0, 0] for _ in range(3)]\u003C\u002Fcode> and keep everything else from the broken version. It passes too. Two fixes, one bug — and only one of them stops the \u003Cem>next\u003C\u002Fem> person from editing a shared point.\u003C\u002Fp>\n","\u003Cul>\n\u003Cli>\u003Ccode>[item] * 3\u003C\u002Fcode> repeats the reference, not the value, so all three entries point at one object.\u003C\u002Fli>\n\u003Cli>Mutating any of them mutates all of them; the bug is invisible until you print every entry.\u003C\u002Fli>\n\u003Cli>A tuple cannot be changed, so sharing one between entries cannot go wrong — that is its main job.\u003C\u002Fli>\n\u003Cli>\u003Ccode>x, y = point\u003C\u002Fcode> unpacks, and a tuple can be a dict key because it is hashable.\u003C\u002Fli>\n\u003Cli>Reach for a tuple for fixed records (a coordinate, an RGB colour, a row you never edit) and a list for anything you intend to grow or edit.\u003C\u002Fli>\n\u003C\u002Ful>\n",[166,171,176,181,200,218],{"id":71,"title":72,"title_en":8,"slug":73,"excerpt":74,"excerpt_en":8,"has_translation":11,"published_at":75,"reading_time":76,"hidden_from_listing":11,"tags":77,"thumbnail_image":8,"og_image":80,"series":167,"authors":168},{"id":82,"title":83,"title_en":84,"slug":85},[169],{"authors_id":170},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},{"id":107,"title":108,"title_en":8,"slug":109,"excerpt":110,"excerpt_en":8,"has_translation":11,"published_at":111,"reading_time":76,"hidden_from_listing":11,"tags":112,"thumbnail_image":8,"og_image":114,"series":172,"authors":173},{"id":82,"title":83,"title_en":84,"slug":85},[174],{"authors_id":175},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},{"id":90,"title":91,"title_en":8,"slug":92,"excerpt":93,"excerpt_en":8,"has_translation":11,"published_at":94,"reading_time":76,"hidden_from_listing":11,"tags":95,"thumbnail_image":8,"og_image":97,"series":177,"authors":178},{"id":82,"title":83,"title_en":84,"slug":85},[179],{"authors_id":180},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},{"id":182,"title":183,"title_en":8,"slug":184,"excerpt":185,"excerpt_en":8,"has_translation":11,"published_at":186,"reading_time":13,"hidden_from_listing":11,"tags":187,"thumbnail_image":8,"og_image":194,"series":195,"authors":197},129,"Biar RAG nggak kena 504: pisahin jalur query dan ingestion","rag-pisah-jalur-query-dan-ingestion","Satu service RAG yang merangkap parsing dan menjawab kueri bakal tumbang pas ada yang upload PDF 200 halaman. Obatnya dua jalur dan satu queue.","2026-10-22T01:30:00.000Z",[188,189,190,191,192,193],"rag","cloud-run","cloud-tasks","gcp","serverless","arsitektur","\u002Fog\u002Frag-pisah-jalur-query-dan-ingestion.png",{"id":196,"title":32,"title_en":33,"slug":34},8,[198],{"authors_id":199},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},{"id":201,"title":202,"title_en":8,"slug":203,"excerpt":204,"excerpt_en":8,"has_translation":11,"published_at":205,"reading_time":76,"hidden_from_listing":11,"tags":206,"thumbnail_image":8,"og_image":213,"series":214,"authors":215},128,"Linear atau graf: cara mengatur banyak agent tanpa loop abadi","multi-agen-linear-atau-grafik","Satu agent dengan dua puluh tool gampang kacau. Begitu beberapa agent saling revisi, kamu butuh graf yang mendukung cycle dan angka yang membuatnya berhenti.","2026-10-21T16:05:00.000Z",[207,208,209,210,211,212],"multi-agent","langgraph","autogen","orkestrasi","checkpoint","llm","\u002Fog\u002Fmulti-agen-linear-atau-grafik.png",{"id":196,"title":32,"title_en":33,"slug":34},[216],{"authors_id":217},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},{"id":219,"title":220,"title_en":8,"slug":221,"excerpt":222,"excerpt_en":8,"has_translation":11,"published_at":223,"reading_time":76,"hidden_from_listing":11,"tags":224,"thumbnail_image":8,"og_image":230,"series":231,"authors":232},127,"Kenapa RAG yang cuma andalkan cosine similarity sering nyasar","kenapa-rag-cuma-cosine-similarity-sering-nyasar","RAG yang cuma andalkan embedding balikin chunk yang mirip maknanya, bukan yang kamu butuh. Ini penyebabnya, dan dua lapis penambalnya.","2026-10-19T02:04:06.718Z",[188,225,226,227,228,229],"vector-search","bm25","hybrid-search","retrieval","embedding","\u002Fog\u002Fkenapa-rag-cuma-cosine-similarity-sering-nyasar.png",{"id":196,"title":32,"title_en":33,"slug":34},[233],{"authors_id":234},{"id":102,"name":103,"slug":104,"role":105,"profile_picture":8},[236,240,243,246,249],{"text":237,"depth":238,"id":239},"Two files, one command",2,"two-files-one-command",{"text":241,"depth":238,"id":242},"* 3 copies the name, not the list","3-copies-the-name-not-the-list",{"text":244,"depth":238,"id":245},"A tuple is the same idea with the door welded shut","a-tuple-is-the-same-idea-with-the-door-welded-shut",{"text":247,"depth":238,"id":248},"Where tuples earn their place","where-tuples-earn-their-place",{"text":250,"depth":238,"id":251},"Before the next article","before-the-next-article",1793246466902]