[{"data":1,"prerenderedAt":282},["ShallowReactive",2],{"tag-labels":3,"site-header":4,"article-python-modules-id":72},{},{"featuredPost":5,"navigations":29},{"id":6,"title":7,"title_id":8,"slug":9,"excerpt":10,"excerpt_id":11,"has_translation":12,"published_at":13,"reading_time":14,"hidden_from_listing":15,"tags":16,"thumbnail_image":21,"og_image":22,"series":23,"authors":28},110,"When You Pick a Framework Just to Look Different","Ketika Pilih Framework Cuma Biar Kelihatan Beda","ketika-pilih-framework-cuma-biar-kelihatan-beda","The last time you chose a new framework or library, was it because your problem needed that tool, or because it sounded cool and few people around you were using it? That question is uncomfortable. Technology decisions are often made for reasons that never appear in any technical document.","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.",true,"2026-10-06T15:25:21.000Z",5,false,[17,18,19,20],"karier","framework","opini","pengalaman",null,"\u002Fog\u002Fketika-pilih-framework-cuma-biar-kelihatan-beda.png",{"id":24,"title":25,"title_id":26,"slug":27},9,"Articles","Artikel","all",[],[30,46,67],{"collection":31,"item":32},"series",{"__typename":31,"title":25,"title_id":26,"slug":27,"children_series":33},[34,38,42],{"title":35,"title_id":36,"slug":37},"Artificial Intelligence","Kecerdasan Artifisial","kecerdasan-artifisial",{"title":39,"title_id":40,"slug":41},"Programming Fundamentals","Konsep Dasar Pemrograman","konsep-dasar-pemrograman",{"title":43,"title_id":44,"slug":45},"Algorithms and Data Structures","Algoritma dan Struktur Data","algoritma-struktur-data",{"collection":31,"item":47},{"__typename":31,"title":48,"title_id":48,"slug":49,"children_series":50},"Tutorial","tutorial",[51,55,59,63],{"title":52,"title_id":53,"slug":54},"Learning Python","Belajar Python","belajar-python",{"title":56,"title_id":57,"slug":58},"Learning Go","Belajar Golang","belajar-golang",{"title":60,"title_id":61,"slug":62},"Learning Java","Belajar Java","belajar-java",{"title":64,"title_id":65,"slug":66},"Learning Pascal","Belajar Pascal","belajar-pascal",{"collection":31,"item":68},{"__typename":31,"title":69,"title_id":69,"slug":70,"children_series":71},"Lab","lab",[],{"article":73,"renderedBody":175,"renderedTakeaway":176,"latestArticles":177,"toc":262},{"id":74,"title":75,"title_id":75,"slug":76,"excerpt":77,"excerpt_id":77,"has_translation":12,"published_at":78,"reading_time":79,"hidden_from_listing":15,"tags":80,"thumbnail_image":21,"og_image":83,"series":84,"authors":167,"seoTitle":21,"seoDescription":21,"body_locale":170,"available_locales":171,"body":173,"takeway":174,"prerequisite":21},136,"Modul Python: Import yang Mencetak Laporannya","python-modules","Kamu memindahkan satu fungsi ke file sendiri, meng-import-nya, dan seluruh laporan jalan lagi lalu memakan inputmu. Modul adalah file, `import` menjalankannya dari atas ke bawah, dan satu baris menentukan pekerjaan mana yang sedang dijalankan file itu.","2026-11-06T01:00:00.000Z",7,[81,82],"python","modules","\u002Fog\u002Fpython-modules.png",{"id":85,"title":86,"title_id":87,"slug":88,"description":89,"description_id":90,"articles":91,"children_series":136,"parent_series":137},18,"Working with Python Scripts","Menggunakan Script Python","python-pemrograman-dengan-script","Leave the interpreter and start writing real .py files, including how to take input and print output.","Keluar dari interpreter dan mulai nulis file .py sendiri, lengkap dengan cara mengambil input dan menampilkan output.",[92,113,129],{"id":93,"title":94,"title_id":95,"slug":96,"excerpt":97,"excerpt_id":98,"has_translation":12,"published_at":99,"reading_time":100,"hidden_from_listing":15,"tags":101,"thumbnail_image":21,"og_image":104,"series":105,"authors":106},90,"Writing and Running a Python Script","Menulis dan Menjalankan Script Python","menulis-dan-menjalankan-script-python","A Python script is a file holding Python code, and it usually carries the .py extension.","Script python merupakan file berisi kode dengan bahasa Python yang biasanya memiliki ekstensi .py","2021-03-21T14:49:24.000Z",4,[81,49,102,103],"tooling","cli","\u002Fog\u002Fmenulis-dan-menjalankan-script-python.png",{"id":85,"title":86,"title_id":87,"slug":88},[107],{"authors_id":108},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},1,"Daffa Izzuddin","izzudd","Writer",{"id":114,"title":115,"title_id":116,"slug":117,"excerpt":118,"excerpt_id":119,"has_translation":12,"published_at":120,"reading_time":100,"hidden_from_listing":15,"tags":121,"thumbnail_image":21,"og_image":124,"series":125,"authors":126},91,"Input and Output Systems in Python 3","Sistem Input dan Output pada Python 3","sistem-input-dan-output-pada-python-3","A few functions, print() and input() among them, are the standard tools most I\u002FO work in Python is built on.","Beberapa fungsi seperti print() dan input(), merupakan fungsi standar yang banyak digunakan untuk melakukan I\u002FO.","2021-05-19T14:57:25.000Z",[81,122,123],"input-output","dasar","\u002Fog\u002Fsistem-input-dan-output-pada-python-3.png",{"id":85,"title":86,"title_id":87,"slug":88},[127],{"authors_id":128},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},{"id":74,"title":130,"title_id":75,"slug":76,"excerpt":131,"excerpt_id":77,"has_translation":12,"published_at":78,"reading_time":79,"hidden_from_listing":15,"tags":80,"thumbnail_image":21,"og_image":83,"series":132,"authors":133},"Python Modules: the Import That Printed the Report","You pull one function out into its own file, import it, and the whole report runs again and eats your input. A module is a file, `import` runs it top to bottom, and one line decides which of the two jobs it is doing.",{"id":85,"title":86,"title_id":87,"slug":88},[134],{"authors_id":135},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},[],{"id":138,"title":52,"title_id":53,"slug":54,"parent_series":139,"children_series":140},10,{"id":109,"title":48,"title_id":48,"slug":49},[141,146,151,152,157,162],{"id":142,"title":143,"title_id":144,"slug":145,"cover_image":21},16,"Getting Started with Python","Berkenalan dengan Bahasa Python","python-intro",{"id":147,"title":148,"title_id":149,"slug":150,"cover_image":21},17,"Variables, Types, and Operations","Variabel, Tipe Data, dan Operasi","python-variabel-tipe-data",{"id":85,"title":86,"title_id":87,"slug":88,"cover_image":21},{"id":153,"title":154,"title_id":155,"slug":156,"cover_image":21},19,"Control Structures","Struktur Kontrol","python-struktur-kontrol",{"id":158,"title":159,"title_id":160,"slug":161,"cover_image":21},20,"Functional Programming with Python","Pemrograman Fungsional dengan Python","python-pemrograman-fungsional",{"id":163,"title":164,"title_id":165,"slug":166,"cover_image":21},30,"Collections and Strings","Koleksi dan String","python-collections",[168],{"authors_id":169},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},"id",[172,170],"en","\nModul itu cuma file Python yang bisa di-import oleh file lain, supaya isinya bisa dipakai ulang tanpa disalin. File `.py` apa pun yang sudah pernah kamu tulis sudah termasuk modul. Kamu memindahkan laporan ke `report.py`, dan file kedua butuh satu fungsi dari situ. Jadi kamu menaruh `import report` di bagian atas lalu menjalankan file kedua itu.\n\nImport-nya menjalankan seluruh laporan. Ia membaca inputmu dulu, lalu mencetak setiap baris dan totalnya, semuanya sebelum file kedua sampai ke baris berikutnya. Tidak ada error yang muncul, jadi tidak ada yang memberi tahu kenapa.\n\nSebabnya satu aturan tentang apa yang dilakukan `import`, dan perbaikannya satu baris plus sedikit penataan ulang. Kamu akan melihat keduanya gagal lalu lulus.\n\n## Dua file, satu perintah\n\nAturannya sama seperti di artikel-artikel sebelumnya, misalnya [Python Dictionaries: the Key That Isn't There](\u002Fp\u002Fpython-dictionary). Kamu menulis programnya, artikelnya memberimu checker, dan kamu menjalankan checker itu sampai berubah dari merah ke hijau. Kamu butuh dua file dan `python3`. Tidak ada repository, tidak ada Docker, tidak ada akun.\n\nSimpan ini sebagai `report.py`. Isinya skripmu apa adanya, dengan laporan di level atas:\n\n```python\n# report.py\nimport sys\n\nrows = []\nfor line in sys.stdin:\n    line = line.strip()\n    if not line:\n        continue\n    name, qty = line.split(\",\")\n    rows.append((name, int(qty)))\n\ntotal = sum(qty for _, qty in rows)\nprint(\"item,qty\")\nfor name, qty in rows:\n    print(f\"{name},{qty}\")\nprint(f\"total,{total}\")\n```\n\n## Apa yang dilakukan import pada sebuah file\n\nNama file adalah nama yang kamu import: `report.py` di-import sebagai `report`, tanpa `.py`.\n\nWaktu Python menemui `import report`, ia mencari filenya lalu menjalankannya dari atas ke bawah, saat itu juga. Ini terjadi sekali per proses. Setiap baris di level atas dijalankan: loop atas `sys.stdin`, `sum`, tiap `print`. Python tidak tahu baris mana yang kamu maksud sebagai bagian yang bisa dipakai ulang.\n\nDari mana ia mencari filenya? Folder skrip yang kamu jalankan ada paling depan di jalur import. Saya cek dengan probe satu baris di folder bernama `probe`. Saat menjalankan `python3 path_probe.py` di situ, `sys.path[0]` berisi basename `probe`. Itu sebabnya dua file dalam satu folder bisa saling import tanpa setup apa pun.\n\nSekarang versi awalnya, di-import. Ia mencetak laporan lengkap: `item,qty`, `kopi,3`, `teh,2`, `kopi,4`, `total,9`. Ada masalah kedua juga. `total` adalah angka yang sudah jadi, bukan fungsi, jadi memanggilnya memunculkan `TypeError: 'int' object is not callable`.\n\nSimpan checker-nya di sebelah `report.py`. Ia memberi program itu `kopi,3`, `teh,2`, dan `kopi,4`, dan mengharapkan total 9. Ia menjalankan filemu sekali sebagai skrip dan dua kali sebagai import.\n\n```python\n# check_report.py\nimport subprocess\nimport sys\n\nDATA = \"\"\"kopi,3\nteh,2\nkopi,4\n\"\"\"\n\nEXPECTED = \"\"\"item,qty\nkopi,3\nteh,2\nkopi,4\ntotal,9\"\"\"\n\n\ndef run(args, stdin=\"\"):\n    return subprocess.run(\n        [sys.executable] + args,\n        input=stdin,\n        text=True,\n        capture_output=True,\n    )\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    as_script = run([\"report.py\"], DATA)\n    as_import = run([\"-c\", \"import report\"], DATA)\n    as_call = run([\"-c\", \"import report; print(report.total([('a', 1), ('b', 2)]))\"])\n\n    stderr_script = as_script.stderr.strip().splitlines()\n    results = [\n        (\"the script runs without crashing\", as_script.returncode == 0,\n         stderr_script[-1] if stderr_script else \"\"),\n        (\"the script prints the report, total last\", as_script.stdout.strip() == EXPECTED,\n         repr(as_script.stdout)),\n        (\"importing it does not crash\", as_import.returncode == 0, as_import.stderr.strip()),\n        (\"importing it prints nothing\", as_import.stdout == \"\", repr(as_import.stdout)),\n        (\"total() is a function you can call\", as_call.returncode == 0 and as_call.stdout.strip() == \"3\",\n         as_call.stderr.strip().splitlines()[-1] if as_call.stderr.strip() else repr(as_call.stdout)),\n    ]\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\nJalankan:\n\n```\npython3 check_report.py\n```\n\n```\nPASS  the script runs without crashing\nPASS  the script prints the report, total last\nPASS  importing it does not crash\nFAIL  importing it prints nothing  \u003C- 'item,qty\\nkopi,3\\nteh,2\\nkopi,4\\ntotal,9\\n'\nFAIL  total() is a function you can call  \u003C- TypeError: 'int' object is not callable\n\n3 of 5 checks passed\n```\n\nExit code-nya 1. Kalau dijalankan sebagai skrip, filenya baik-baik saja. Kedua kegagalan datang dari import, dan yang pertama menunjukkan seluruh laporan yang bocor keluar.\n\n## Satu baris menentukan pekerjaan file itu\n\nPython memberi setiap file sebuah nama selama ia berjalan. Nama itu ada di `__name__`. Isinya `__main__` kalau kamu menjalankan filenya sendiri, dan nama modul kalau ada yang meng-import-nya.\n\nTaruh satu baris, `print(__name__)`, di file bernama `name_probe.py`. Jalankan `python3 name_probe.py` dan ia mencetak `__main__`. Import dari file lain, dan baris yang sama mencetak `name_probe`.\n\nKodenya identik dan namanya berbeda. Baris `if __name__ == \"__main__\":` membandingkan dua string itu. Kalau cocok, blok yang menjorok dijalankan. Kalau file lain yang meng-import punyamu, keduanya tidak cocok dan blok itu dilewati.\n\nJadi rencananya punya dua bagian. Taruh pekerjaan di dalam fungsi, karena `def` cuma mengikat nama saat file di-import. Lalu taruh satu pemanggilan yang memulai pekerjaan itu di bawah guard.\n\n## Perbaikannya\n\nSaya pecah versi awal jadi tiga fungsi. `parse` membaca barisnya, `total` menjumlahkannya, dan `main` mencetak laporan. Sekarang `total` adalah fungsi, dan itu menghapus `TypeError` tadi. Dua baris terakhir memegang guard-nya.\n\n```python\n# report.py\nimport sys\n\n\ndef parse(lines):\n    rows = []\n    for line in lines:\n        line = line.strip()\n        if not line:\n            continue\n        name, qty = line.split(\",\")\n        rows.append((name, int(qty)))\n    return rows\n\n\ndef total(rows):\n    return sum(qty for _, qty in rows)\n\n\ndef main():\n    rows = parse(sys.stdin)\n    print(\"item,qty\")\n    for name, qty in rows:\n        print(f\"{name},{qty}\")\n    print(f\"total,{total(rows)}\")\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\nJalankan checker-nya lagi:\n\n```\npython3 check_report.py\n```\n\n```\nPASS  the script runs without crashing\nPASS  the script prints the report, total last\nPASS  importing it does not crash\nPASS  importing it prints nothing\nPASS  total() is a function you can call\n\n5 of 5 checks passed\n```\n\nExit code-nya 0.\n\n## Yang tidak dilakukan ini\n\nPackage adalah folder dengan file `__init__.py`, dan relative import adalah bentuk `from . import` yang dipakai di dalamnya. Keduanya untuk nanti. Dua file dalam satu folder tidak butuh keduanya.\n\nGuard juga tidak menyelamatkan `print` yang kamu tinggalkan di level modul. Kalau ada `print(\"debug\")` liar di luar semua fungsi dan di luar guard, setiap proses yang meng-import file itu mencetaknya sekali. Guard hanya melindungi baris yang menjorok di bawahnya.\n\n## Sebelum artikel berikutnya\n\nHapus dua baris terakhir dari file yang sudah diperbaiki: baris `if __name__ == \"__main__\":` dan pemanggilan `main()` di bawahnya. Jalankan checker-nya lagi. Saya ukur 4 dari 5 dan exit code 1, dan satu-satunya kegagalan adalah ini:\n\n```\nFAIL  the script prints the report, total last  \u003C- ''\n```\n\nSkripnya jalan dan tidak mencetak apa pun. Sekarang kembalikan kedua baris itu dan jalankan checker sampai ia bilang 5 dari 5 lagi.\n\nItu membuktikan checker bisa membedakan file yang dijalankan dan yang cuma di-import. Ia tidak bisa membuktikan kode di dalam `main()` benar.\n\nKalau `import` menjalankan seluruh file, apa lagi di skrip lamamu yang selama ini sudah berjalan di level atas?\n","- `import report` menjalankan seluruh file dari atas ke bawah saat itu juga, jadi pekerjaan di level atas terjadi lagi di dalam file yang meng-import-nya.\n- `__name__` bernilai `__main__` kalau kamu menjalankan filenya sendiri, dan bernilai nama modul kalau ada yang meng-import; guard membandingkan dua string itu.\n- Pekerjaan sebaiknya ada di dalam fungsi, karena `def` cuma mengikat nama, dan pemanggilan di bawah `if __name__ == \"__main__\":` yang memulainya.\n- Nilai yang dihitung di level modul selesai sekali saja: `total` di versi awal adalah angka 9, jadi memanggilnya memunculkan `TypeError: 'int' object is not callable`.\n- Guard hanya melindungi baris yang menjorok di bawahnya, jadi `print` liar di level atas tetap jalan setiap kali file di-import.","\u003Cp>Modul itu cuma file Python yang bisa di-import oleh file lain, supaya isinya bisa dipakai ulang tanpa disalin. File \u003Ccode>.py\u003C\u002Fcode> apa pun yang sudah pernah kamu tulis sudah termasuk modul. Kamu memindahkan laporan ke \u003Ccode>report.py\u003C\u002Fcode>, dan file kedua butuh satu fungsi dari situ. Jadi kamu menaruh \u003Ccode>import report\u003C\u002Fcode> di bagian atas lalu menjalankan file kedua itu.\u003C\u002Fp>\n\u003Cp>Import-nya menjalankan seluruh laporan. Ia membaca inputmu dulu, lalu mencetak setiap baris dan totalnya, semuanya sebelum file kedua sampai ke baris berikutnya. Tidak ada error yang muncul, jadi tidak ada yang memberi tahu kenapa.\u003C\u002Fp>\n\u003Cp>Sebabnya satu aturan tentang apa yang dilakukan \u003Ccode>import\u003C\u002Fcode>, dan perbaikannya satu baris plus sedikit penataan ulang. Kamu akan melihat keduanya gagal lalu lulus.\u003C\u002Fp>\n\u003Ch2 id=\"dua-file-satu-perintah\">Dua file, satu perintah\u003C\u002Fh2>\n\u003Cp>Aturannya sama seperti di artikel-artikel sebelumnya, misalnya \u003Ca href=\"\u002Fp\u002Fpython-dictionary\">Python Dictionaries: the Key That Isn&#39;t There\u003C\u002Fa>. Kamu menulis programnya, artikelnya memberimu checker, dan kamu menjalankan checker itu sampai berubah dari merah ke hijau. Kamu butuh dua file dan \u003Ccode>python3\u003C\u002Fcode>. Tidak ada repository, tidak ada Docker, tidak ada akun.\u003C\u002Fp>\n\u003Cp>Simpan ini sebagai \u003Ccode>report.py\u003C\u002Fcode>. Isinya skripmu apa adanya, dengan laporan di level atas:\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%20report.py%0Aimport%20sys%0A%0Arows%20%3D%20%5B%5D%0Afor%20line%20in%20sys.stdin%3A%0A%20%20%20%20line%20%3D%20line.strip()%0A%20%20%20%20if%20not%20line%3A%0A%20%20%20%20%20%20%20%20continue%0A%20%20%20%20name%2C%20qty%20%3D%20line.split(%22%2C%22)%0A%20%20%20%20rows.append((name%2C%20int(qty)))%0A%0Atotal%20%3D%20sum(qty%20for%20_%2C%20qty%20in%20rows)%0Aprint(%22item%2Cqty%22)%0Afor%20name%2C%20qty%20in%20rows%3A%0A%20%20%20%20print(f%22%7Bname%7D%2C%7Bqty%7D%22)%0Aprint(f%22total%2C%7Btotal%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\"># report.py\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:#E1E4E8\">rows \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> []\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\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\"> sys.stdin:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    line \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> line.strip()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    if\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> not\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> line:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">        continue\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    name, qty \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> line.split(\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\",\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    rows.append((name, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">int\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(qty)))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">total \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> sum\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(qty \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> _, qty \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> rows)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"item,qty\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> name, qty \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> rows:\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\">name\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">qty\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:#79B8FF\">print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"total,\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">total\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>\u003Ch2 id=\"apa-yang-dilakukan-import-pada-sebuah-file\">Apa yang dilakukan import pada sebuah file\u003C\u002Fh2>\n\u003Cp>Nama file adalah nama yang kamu import: \u003Ccode>report.py\u003C\u002Fcode> di-import sebagai \u003Ccode>report\u003C\u002Fcode>, tanpa \u003Ccode>.py\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Waktu Python menemui \u003Ccode>import report\u003C\u002Fcode>, ia mencari filenya lalu menjalankannya dari atas ke bawah, saat itu juga. Ini terjadi sekali per proses. Setiap baris di level atas dijalankan: loop atas \u003Ccode>sys.stdin\u003C\u002Fcode>, \u003Ccode>sum\u003C\u002Fcode>, tiap \u003Ccode>print\u003C\u002Fcode>. Python tidak tahu baris mana yang kamu maksud sebagai bagian yang bisa dipakai ulang.\u003C\u002Fp>\n\u003Cp>Dari mana ia mencari filenya? Folder skrip yang kamu jalankan ada paling depan di jalur import. Saya cek dengan probe satu baris di folder bernama \u003Ccode>probe\u003C\u002Fcode>. Saat menjalankan \u003Ccode>python3 path_probe.py\u003C\u002Fcode> di situ, \u003Ccode>sys.path[0]\u003C\u002Fcode> berisi basename \u003Ccode>probe\u003C\u002Fcode>. Itu sebabnya dua file dalam satu folder bisa saling import tanpa setup apa pun.\u003C\u002Fp>\n\u003Cp>Sekarang versi awalnya, di-import. Ia mencetak laporan lengkap: \u003Ccode>item,qty\u003C\u002Fcode>, \u003Ccode>kopi,3\u003C\u002Fcode>, \u003Ccode>teh,2\u003C\u002Fcode>, \u003Ccode>kopi,4\u003C\u002Fcode>, \u003Ccode>total,9\u003C\u002Fcode>. Ada masalah kedua juga. \u003Ccode>total\u003C\u002Fcode> adalah angka yang sudah jadi, bukan fungsi, jadi memanggilnya memunculkan \u003Ccode>TypeError: &#39;int&#39; object is not callable\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Simpan checker-nya di sebelah \u003Ccode>report.py\u003C\u002Fcode>. Ia memberi program itu \u003Ccode>kopi,3\u003C\u002Fcode>, \u003Ccode>teh,2\u003C\u002Fcode>, dan \u003Ccode>kopi,4\u003C\u002Fcode>, dan mengharapkan total 9. Ia menjalankan filemu sekali sebagai skrip dan dua kali sebagai import.\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_report.py%0Aimport%20subprocess%0Aimport%20sys%0A%0ADATA%20%3D%20%22%22%22kopi%2C3%0Ateh%2C2%0Akopi%2C4%0A%22%22%22%0A%0AEXPECTED%20%3D%20%22%22%22item%2Cqty%0Akopi%2C3%0Ateh%2C2%0Akopi%2C4%0Atotal%2C9%22%22%22%0A%0A%0Adef%20run(args%2C%20stdin%3D%22%22)%3A%0A%20%20%20%20return%20subprocess.run(%0A%20%20%20%20%20%20%20%20%5Bsys.executable%5D%20%2B%20args%2C%0A%20%20%20%20%20%20%20%20input%3Dstdin%2C%0A%20%20%20%20%20%20%20%20text%3DTrue%2C%0A%20%20%20%20%20%20%20%20capture_output%3DTrue%2C%0A%20%20%20%20)%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%20as_script%20%3D%20run(%5B%22report.py%22%5D%2C%20DATA)%0A%20%20%20%20as_import%20%3D%20run(%5B%22-c%22%2C%20%22import%20report%22%5D%2C%20DATA)%0A%20%20%20%20as_call%20%3D%20run(%5B%22-c%22%2C%20%22import%20report%3B%20print(report.total(%5B('a'%2C%201)%2C%20('b'%2C%202)%5D))%22%5D)%0A%0A%20%20%20%20stderr_script%20%3D%20as_script.stderr.strip().splitlines()%0A%20%20%20%20results%20%3D%20%5B%0A%20%20%20%20%20%20%20%20(%22the%20script%20runs%20without%20crashing%22%2C%20as_script.returncode%20%3D%3D%200%2C%0A%20%20%20%20%20%20%20%20%20stderr_script%5B-1%5D%20if%20stderr_script%20else%20%22%22)%2C%0A%20%20%20%20%20%20%20%20(%22the%20script%20prints%20the%20report%2C%20total%20last%22%2C%20as_script.stdout.strip()%20%3D%3D%20EXPECTED%2C%0A%20%20%20%20%20%20%20%20%20repr(as_script.stdout))%2C%0A%20%20%20%20%20%20%20%20(%22importing%20it%20does%20not%20crash%22%2C%20as_import.returncode%20%3D%3D%200%2C%20as_import.stderr.strip())%2C%0A%20%20%20%20%20%20%20%20(%22importing%20it%20prints%20nothing%22%2C%20as_import.stdout%20%3D%3D%20%22%22%2C%20repr(as_import.stdout))%2C%0A%20%20%20%20%20%20%20%20(%22total()%20is%20a%20function%20you%20can%20call%22%2C%20as_call.returncode%20%3D%3D%200%20and%20as_call.stdout.strip()%20%3D%3D%20%223%22%2C%0A%20%20%20%20%20%20%20%20%20as_call.stderr.strip().splitlines()%5B-1%5D%20if%20as_call.stderr.strip()%20else%20repr(as_call.stdout))%2C%0A%20%20%20%20%5D%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_report.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\">DATA\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"\"\"kopi,3\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">teh,2\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">kopi,4\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">\"\"\"\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:#9ECBFF\"> \"\"\"item,qty\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">kopi,3\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">teh,2\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">kopi,4\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">total,9\"\"\"\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\"> run\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(args, stdin\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">):\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> subprocess.run(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        [sys.executable] \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> args,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">        input\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">stdin,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\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>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\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\">    )\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\">    as_script \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> run([\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"report.py\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">], \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">DATA\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    as_import \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> run([\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"-c\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"import report\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">], \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">DATA\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    as_call \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> run([\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"-c\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"import report; print(report.total([('a', 1), ('b', 2)]))\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">])\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    stderr_script \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> as_script.stderr.strip().splitlines()\u003C\u002Fspan>\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>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        (\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"the script runs without crashing\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, as_script.returncode \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\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\">         stderr_script[\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\"> stderr_script \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        (\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"the script prints the report, total last\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, as_script.stdout.strip() \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> EXPECTED\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">         repr\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(as_script.stdout)),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        (\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"importing it does not crash\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, as_import.returncode \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 0\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, as_import.stderr.strip()),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        (\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"importing it prints nothing\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, as_import.stdout \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">repr\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(as_import.stdout)),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        (\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"total() is a function you can call\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, as_call.returncode \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> 0\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> and\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> as_call.stdout.strip() \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">==\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\"> \"3\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">         as_call.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\"> as_call.stderr.strip() \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> repr\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(as_call.stdout)),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    ]\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>\u003Cp>Jalankan:\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\">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=\"python3%20check_report.py\" 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_report.py\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=\"PASS%20%20the%20script%20runs%20without%20crashing%0APASS%20%20the%20script%20prints%20the%20report%2C%20total%20last%0APASS%20%20importing%20it%20does%20not%20crash%0AFAIL%20%20importing%20it%20prints%20nothing%20%20%3C-%20'item%2Cqty%5Cnkopi%2C3%5Cnteh%2C2%5Cnkopi%2C4%5Cntotal%2C9%5Cn'%0AFAIL%20%20total()%20is%20a%20function%20you%20can%20call%20%20%3C-%20TypeError%3A%20'int'%20object%20is%20not%20callable%0A%0A3%20of%205%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>PASS  the script runs without crashing\nPASS  the script prints the report, total last\nPASS  importing it does not crash\nFAIL  importing it prints nothing  &lt;- 'item,qty\\nkopi,3\\nteh,2\\nkopi,4\\ntotal,9\\n'\nFAIL  total() is a function you can call  &lt;- TypeError: 'int' object is not callable\n\n3 of 5 checks passed\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Exit code-nya 1. Kalau dijalankan sebagai skrip, filenya baik-baik saja. Kedua kegagalan datang dari import, dan yang pertama menunjukkan seluruh laporan yang bocor keluar.\u003C\u002Fp>\n\u003Ch2 id=\"satu-baris-menentukan-pekerjaan-file-itu\">Satu baris menentukan pekerjaan file itu\u003C\u002Fh2>\n\u003Cp>Python memberi setiap file sebuah nama selama ia berjalan. Nama itu ada di \u003Ccode>__name__\u003C\u002Fcode>. Isinya \u003Ccode>__main__\u003C\u002Fcode> kalau kamu menjalankan filenya sendiri, dan nama modul kalau ada yang meng-import-nya.\u003C\u002Fp>\n\u003Cp>Taruh satu baris, \u003Ccode>print(__name__)\u003C\u002Fcode>, di file bernama \u003Ccode>name_probe.py\u003C\u002Fcode>. Jalankan \u003Ccode>python3 name_probe.py\u003C\u002Fcode> dan ia mencetak \u003Ccode>__main__\u003C\u002Fcode>. Import dari file lain, dan baris yang sama mencetak \u003Ccode>name_probe\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Kodenya identik dan namanya berbeda. Baris \u003Ccode>if __name__ == &quot;__main__&quot;:\u003C\u002Fcode> membandingkan dua string itu. Kalau cocok, blok yang menjorok dijalankan. Kalau file lain yang meng-import punyamu, keduanya tidak cocok dan blok itu dilewati.\u003C\u002Fp>\n\u003Cp>Jadi rencananya punya dua bagian. Taruh pekerjaan di dalam fungsi, karena \u003Ccode>def\u003C\u002Fcode> cuma mengikat nama saat file di-import. Lalu taruh satu pemanggilan yang memulai pekerjaan itu di bawah guard.\u003C\u002Fp>\n\u003Ch2 id=\"perbaikannya\">Perbaikannya\u003C\u002Fh2>\n\u003Cp>Saya pecah versi awal jadi tiga fungsi. \u003Ccode>parse\u003C\u002Fcode> membaca barisnya, \u003Ccode>total\u003C\u002Fcode> menjumlahkannya, dan \u003Ccode>main\u003C\u002Fcode> mencetak laporan. Sekarang \u003Ccode>total\u003C\u002Fcode> adalah fungsi, dan itu menghapus \u003Ccode>TypeError\u003C\u002Fcode> tadi. Dua baris terakhir memegang guard-nya.\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%20report.py%0Aimport%20sys%0A%0A%0Adef%20parse(lines)%3A%0A%20%20%20%20rows%20%3D%20%5B%5D%0A%20%20%20%20for%20line%20in%20lines%3A%0A%20%20%20%20%20%20%20%20line%20%3D%20line.strip()%0A%20%20%20%20%20%20%20%20if%20not%20line%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20name%2C%20qty%20%3D%20line.split(%22%2C%22)%0A%20%20%20%20%20%20%20%20rows.append((name%2C%20int(qty)))%0A%20%20%20%20return%20rows%0A%0A%0Adef%20total(rows)%3A%0A%20%20%20%20return%20sum(qty%20for%20_%2C%20qty%20in%20rows)%0A%0A%0Adef%20main()%3A%0A%20%20%20%20rows%20%3D%20parse(sys.stdin)%0A%20%20%20%20print(%22item%2Cqty%22)%0A%20%20%20%20for%20name%2C%20qty%20in%20rows%3A%0A%20%20%20%20%20%20%20%20print(f%22%7Bname%7D%2C%7Bqty%7D%22)%0A%20%20%20%20print(f%22total%2C%7Btotal(rows)%7D%22)%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20main()\" 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\"># report.py\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\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C\u002Fspan>\u003Cspan style=\"color:#B392F0\"> parse\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(lines):\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    rows \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> []\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\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\"> lines:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        line \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> line.strip()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">        if\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\"> not\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> line:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">            continue\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        name, qty \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> line.split(\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\",\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        rows.append((name, \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">int\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(qty)))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> rows\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\"> total\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(rows):\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> sum\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(qty \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> _, qty \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> rows)\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\">    rows \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> parse(sys.stdin)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"item,qty\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    for\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> name, qty \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> rows:\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\">name\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">qty\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:#79B8FF\">    print\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"total,\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">total(rows)\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\">\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\">    main()\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Jalankan checker-nya lagi:\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\">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=\"python3%20check_report.py\" 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_report.py\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=\"PASS%20%20the%20script%20runs%20without%20crashing%0APASS%20%20the%20script%20prints%20the%20report%2C%20total%20last%0APASS%20%20importing%20it%20does%20not%20crash%0APASS%20%20importing%20it%20prints%20nothing%0APASS%20%20total()%20is%20a%20function%20you%20can%20call%0A%0A5%20of%205%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>PASS  the script runs without crashing\nPASS  the script prints the report, total last\nPASS  importing it does not crash\nPASS  importing it prints nothing\nPASS  total() is a function you can call\n\n5 of 5 checks passed\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Exit code-nya 0.\u003C\u002Fp>\n\u003Ch2 id=\"yang-tidak-dilakukan-ini\">Yang tidak dilakukan ini\u003C\u002Fh2>\n\u003Cp>Package adalah folder dengan file \u003Ccode>__init__.py\u003C\u002Fcode>, dan relative import adalah bentuk \u003Ccode>from . import\u003C\u002Fcode> yang dipakai di dalamnya. Keduanya untuk nanti. Dua file dalam satu folder tidak butuh keduanya.\u003C\u002Fp>\n\u003Cp>Guard juga tidak menyelamatkan \u003Ccode>print\u003C\u002Fcode> yang kamu tinggalkan di level modul. Kalau ada \u003Ccode>print(&quot;debug&quot;)\u003C\u002Fcode> liar di luar semua fungsi dan di luar guard, setiap proses yang meng-import file itu mencetaknya sekali. Guard hanya melindungi baris yang menjorok di bawahnya.\u003C\u002Fp>\n\u003Ch2 id=\"sebelum-artikel-berikutnya\">Sebelum artikel berikutnya\u003C\u002Fh2>\n\u003Cp>Hapus dua baris terakhir dari file yang sudah diperbaiki: baris \u003Ccode>if __name__ == &quot;__main__&quot;:\u003C\u002Fcode> dan pemanggilan \u003Ccode>main()\u003C\u002Fcode> di bawahnya. Jalankan checker-nya lagi. Saya ukur 4 dari 5 dan exit code 1, dan satu-satunya kegagalan adalah ini:\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\">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=\"FAIL%20%20the%20script%20prints%20the%20report%2C%20total%20last%20%20%3C-%20''\" 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>FAIL  the script prints the report, total last  &lt;- ''\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Skripnya jalan dan tidak mencetak apa pun. Sekarang kembalikan kedua baris itu dan jalankan checker sampai ia bilang 5 dari 5 lagi.\u003C\u002Fp>\n\u003Cp>Itu membuktikan checker bisa membedakan file yang dijalankan dan yang cuma di-import. Ia tidak bisa membuktikan kode di dalam \u003Ccode>main()\u003C\u002Fcode> benar.\u003C\u002Fp>\n\u003Cp>Kalau \u003Ccode>import\u003C\u002Fcode> menjalankan seluruh file, apa lagi di skrip lamamu yang selama ini sudah berjalan di level atas?\u003C\u002Fp>\n","\u003Cul>\n\u003Cli>\u003Ccode>import report\u003C\u002Fcode> menjalankan seluruh file dari atas ke bawah saat itu juga, jadi pekerjaan di level atas terjadi lagi di dalam file yang meng-import-nya.\u003C\u002Fli>\n\u003Cli>\u003Ccode>__name__\u003C\u002Fcode> bernilai \u003Ccode>__main__\u003C\u002Fcode> kalau kamu menjalankan filenya sendiri, dan bernilai nama modul kalau ada yang meng-import; guard membandingkan dua string itu.\u003C\u002Fli>\n\u003Cli>Pekerjaan sebaiknya ada di dalam fungsi, karena \u003Ccode>def\u003C\u002Fcode> cuma mengikat nama, dan pemanggilan di bawah \u003Ccode>if __name__ == &quot;__main__&quot;:\u003C\u002Fcode> yang memulainya.\u003C\u002Fli>\n\u003Cli>Nilai yang dihitung di level modul selesai sekali saja: \u003Ccode>total\u003C\u002Fcode> di versi awal adalah angka 9, jadi memanggilnya memunculkan \u003Ccode>TypeError: &#39;int&#39; object is not callable\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Guard hanya melindungi baris yang menjorok di bawahnya, jadi \u003Ccode>print\u003C\u002Fcode> liar di level atas tetap jalan setiap kali file di-import.\u003C\u002Fli>\n\u003C\u002Ful>\n",[178,195,200,217,231,247],{"id":179,"title":180,"title_id":181,"slug":182,"excerpt":183,"excerpt_id":184,"has_translation":12,"published_at":78,"reading_time":14,"hidden_from_listing":15,"tags":185,"thumbnail_image":21,"og_image":188,"series":189,"authors":192},137,"Java Operators: the Average That Came Out a Whole Number","Operator Java: Rata-Rata yang Keluar Sebagai Bilangan Bulat","java-operators","Three scores, one division, and the average prints as 82. Both operands are `int`, so the fraction is cut off, and the obvious cast prints `82.0` without fixing anything.","Tiga nilai, satu pembagian, dan rata-ratanya tercetak 82. Kedua operand-nya `int`, jadi pecahannya dipotong, dan cast yang paling wajar malah mencetak `82.0` tanpa memperbaiki apa pun.",[186,187],"java","operator","\u002Fog\u002Fjava-operators.png",{"id":190,"title":148,"title_id":149,"slug":191},22,"java-variabel-tipe-data",[193],{"authors_id":194},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},{"id":74,"title":130,"title_id":75,"slug":76,"excerpt":131,"excerpt_id":77,"has_translation":12,"published_at":78,"reading_time":79,"hidden_from_listing":15,"tags":80,"thumbnail_image":21,"og_image":83,"series":196,"authors":197},{"id":85,"title":86,"title_id":87,"slug":88},[198],{"authors_id":199},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},{"id":201,"title":202,"title_id":21,"slug":203,"excerpt":204,"excerpt_id":21,"has_translation":15,"published_at":205,"reading_time":100,"hidden_from_listing":15,"tags":206,"thumbnail_image":21,"og_image":211,"series":212,"authors":214},135,"Caching That Never Hits Costs More Than No Caching","caching-that-never-hits","Same model, same conversation, same token count, and a bill five times higher. The cause is a prefix that changes, a write premium nobody reads about, and a cost curve that grows faster than the loop.","2026-11-04T01:10:00.000Z",[207,208,209,210],"llm","ai-agent","cache","api","\u002Fog\u002Fcaching-that-never-hits.png",{"id":213,"title":35,"title_id":36,"slug":37},8,[215],{"authors_id":216},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},{"id":218,"title":219,"title_id":21,"slug":220,"excerpt":221,"excerpt_id":21,"has_translation":15,"published_at":222,"reading_time":14,"hidden_from_listing":15,"tags":223,"thumbnail_image":21,"og_image":226,"series":227,"authors":228},134,"Your Stream Dies at 125 Seconds and Nothing in Your Code Says 125","your-stream-dies-at-125-seconds","Streaming moves the wait into a connection that outlives the request. Four layers sit between the model and the browser, their idle timeouts disagree, and the smallest one ends your stream.","2026-11-04T01:00:00.000Z",[224,225,208,210],"streaming","sse","\u002Fog\u002Fyour-stream-dies-at-125-seconds.png",{"id":213,"title":35,"title_id":36,"slug":37},[229],{"authors_id":230},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},{"id":232,"title":233,"title_id":234,"slug":235,"excerpt":236,"excerpt_id":237,"has_translation":12,"published_at":238,"reading_time":239,"hidden_from_listing":15,"tags":240,"thumbnail_image":21,"og_image":242,"series":243,"authors":244},133,"Python Strings: the Badge That Only Worked for One Name","String Python: Badge yang Cuma Jalan untuk Satu Nama","python-strings","The badge script printed the right name for the person who wrote it and the wrong name for everybody else. Slicing counts characters, and a name is words.","Skrip badge mencetak nama yang benar untuk orang yang menulisnya dan nama yang salah untuk semua orang lain. Slicing menghitung karakter, sedangkan nama itu kata.","2026-10-28T13:00:00.000Z",6,[81,241],"string","\u002Fog\u002Fpython-strings.png",{"id":163,"title":164,"title_id":165,"slug":166},[245],{"authors_id":246},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},{"id":248,"title":249,"title_id":250,"slug":251,"excerpt":252,"excerpt_id":253,"has_translation":12,"published_at":254,"reading_time":239,"hidden_from_listing":15,"tags":255,"thumbnail_image":21,"og_image":257,"series":258,"authors":259},132,"Python Tuples: Why All Three Points Are the Same Point","Tuple Python: Kenapa Ketiga Titik Itu Titik yang Sama","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.","Tiga titik masuk ke satu loop dan keluar identik. List-nya nggak pernah disalin tiga kali; yang disalin cuma namanya. Tuple membuat bug ini mustahil terjadi.","2026-10-28T12:00:00.000Z",[81,256],"tuple","\u002Fog\u002Fpython-tuples.png",{"id":163,"title":164,"title_id":165,"slug":166},[260],{"authors_id":261},{"id":109,"name":110,"slug":111,"role":112,"profile_picture":21},[263,267,270,273,276,279],{"text":264,"depth":265,"id":266},"Dua file, satu perintah",2,"dua-file-satu-perintah",{"text":268,"depth":265,"id":269},"Apa yang dilakukan import pada sebuah file","apa-yang-dilakukan-import-pada-sebuah-file",{"text":271,"depth":265,"id":272},"Satu baris menentukan pekerjaan file itu","satu-baris-menentukan-pekerjaan-file-itu",{"text":274,"depth":265,"id":275},"Perbaikannya","perbaikannya",{"text":277,"depth":265,"id":278},"Yang tidak dilakukan ini","yang-tidak-dilakukan-ini",{"text":280,"depth":265,"id":281},"Sebelum artikel berikutnya","sebelum-artikel-berikutnya",1793986940571]