{ "cells": [ { "cell_type": "markdown", "id": "59aa4a03", "metadata": {}, "source": [ "### 文件重命名并放在一个路径下" ] }, { "cell_type": "code", "execution_count": 1, "id": "479a84ce", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "🔍 正在扫描所有文件...\n", "✅ 共找到 66 个实例,总计 90 个文件\n", "📁 正在生成批次 1: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_1\n", "[Batch 1] ✅ FINST-0CC662718BILO83CEX5TJ4OXZP2C3X1PCLRWLFGL.png\n", "[Batch 1] ✅ FINST-0D866I81JANY5WG8A2DT15S63HZH20YFR68FMQJA.png\n", "[Batch 1] ✅ FINST-0HD66Z81DFXYBP816VRKD6S2HA2H3RYCBYKFMR6.jpg\n", "[Batch 1] ✅ FINST-3MF66MB1C62UYQ70B6VFWCC72LWD3WFATRQ8MJF1.jpg\n", "[Batch 1] ✅ FINST-3RB66I91KLXKFLFLFENM3DP0BQER2D0BEAXVLS11.xlsx\n", "[Batch 1] ✅ FINST-3SC66EA1POUU8OOK7YW2GDJEKD972XTSC1V9MCB1.png\n", "[Batch 1] ✅ FINST-42766EA129TVP57F6HGFPAATXT4K2J17LS7BMPS2.png\n", "[Batch 1] ✅ FINST-54A66HC1426KP5L87MXEA682I67O23YKVXUUL9U9.jpg\n", "[Batch 1] ✅ FINST-54A66HC1BDILGOIO8D24RCKSUXOU2641DLRWLFY5.png\n", "[Batch 1] ✅ FINST-54A66HC1NBQSMDDUEDQU4CSW0OJI27EQ2TV6MHV.xlsx\n", "[Batch 1] ✅ FINST-5B866X816C0WLA139FUCS6ISBUCK3KXV3UIBMX22.jpg\n", "[Batch 1] ✅ FINST-5W966981KWJJ06WS8VXCYC10RV7U31E6282ULAHS.png\n", "[Batch 1] ✅ FINST-5X866U8169BBPU9BFDL61ASKGDPW3RJM5LIILSNA.png\n", "[Batch 1] ✅ FINST-65D66X71VHAPFNPZ9OFURCIREZAS28FI7P12MJS.png\n", "[Batch 1] ✅ FINST-69E66NA11AKXLE2R7DOP3AOZM8SD3R64OXNDM7G.png\n", "[Batch 1] ✅ FINST-69E66NA1ATDYE53ADVQ8DCX122G53OQC1ETEM62.png\n", "[Batch 1] ✅ FINST-6B966W917QETCTT5ARDDR8J2IOJD26ZQYVT7M3I.png\n", "[Batch 1] ✅ FINST-8AD662D1X8VOJJUGCZ7NFCI1XLDM3EUX97H1MKJ1.png\n", "[Batch 1] ✅ FINST-8EC66FA15UNNQPWWBOPENDDJ6EQM2MDGX4SZLOP4.jpg\n", "[Batch 1] ✅ FINST-8O866AA142HTFEQ18XDVG5SQ0Y7Z14EVF6Y7MBHB.jpg\n", "[Batch 1] ✅ FINST-9FA66WC1LDJNFROD7HJUI4OJ6C2J22UP25SZLUQA.jpg\n", "[Batch 1] ✅ FINST-AZC667816Z9TV9Z4DD1PDD4OLN5825J8S4O7MOJ1.png\n", "[Batch 1] ✅ FINST-BL866S61XU8DOZG5BZ6E4DZ2UOIV3B6CEHALL3QI.jpg\n", "[Batch 1] ✅ FINST-ETA66681ZAHDHL2OA0MQR6UB9W5N2MZM2DGLLU2.png\n", "[Batch 1] ✅ FINST-FX7660A1N11VJB6IBDBRE8N012ZQ2HVJIWBAMYL2.jpg\n", "[Batch 1] ✅ FINST-G7B66QC1U162UFRMHJFJ59Q5VZZD3VQ1MS4KM0F.png\n", "[Batch 1] ✅ FINST-HI766JB1ORJFF6STEI8PR6E3YJTF2B87VNDOLSM5.xlsx\n", "[Batch 1] ✅ FINST-HRD66W919462UFW0NG4PODHZZUW63074RZAKM1DK.png\n", "[Batch 1] ✅ FINST-IO766F81JX9VU83Z6OR927WUWBUJ3FDQKEGAM0X.xlsx\n", "[Batch 1] ✅ FINST-IQC66GC18W4YQ8GSCL23T582HU1H3960PVGEML8.png\n", "[Batch 1] ✅ FINST-IRD66GC15CA2MFOFM8MHCBN7OSWA3PKSUZAKMKS.png\n", "[Batch 1] ✅ FINST-IRD66PB1X8I2R8DLJKVF9667G4LC3TWHHZLKM0J.png\n", "[Batch 1] ✅ FINST-IUF66391KP8W6U35CG7JL8UC2GK52JXZA6TBM6P.png\n", "[Batch 1] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "[Batch 1] ✅ FINST-J3D66LA13NTHEZAICABNRCD3KVCY222Q7IORL7UD.jpg\n", "[Batch 1] ✅ FINST-JB966E91FW8YJMLMD52WCCZCXO5V28E0JHMEMM.jpg\n", "[Batch 1] ✅ FINST-JXA66PB1ONATQBEIBDMEZ45MLMVB3M0CO6O7MH01.png\n", "[Batch 1] ✅ FINST-JZE66UC1Q8H2F0E3M38EX853TR242SGJFJKKMK8.xlsx\n", "[Batch 1] ✅ FINST-K7E66Z91F5NYOC0UD20BO775JN8C3D763K6FM16.xlsx\n", "[Batch 1] ✅ FINST-KW866QB13VPZ5OSE9CE0LAWVKEO23QA4XVOGM92.jpg\n", "[Batch 1] ✅ FINST-L3D66981YN31J5O8MGQCCCPF6FE82J0EBZMIMQ61.xlsx\n", "[Batch 1] ✅ FINST-LCC66CA1BTTCK1HQ9S8TP91UHORX3JHYWOQKLO65.pptx\n", "[Batch 1] ✅ FINST-LLA66D71DDUN56UUBRVZVD2EO3TS291ZDU00M734.png\n", "[Batch 1] ✅ FINST-NLD66NA171BT4QDDCKR6HBD8XSHG3UJ1FSP7MJ39.png\n", "[Batch 1] ✅ FINST-OPA665A1KV9TAY9UA78YID6X4S4Y2HPA03N7MO3.png\n", "[Batch 1] ✅ FINST-P6D66F71YYMY4D4PE6FL58E9BU8X3JUP0G6FM6R.xlsx\n", "[Batch 1] ✅ FINST-PF866EA1IKDECQEC8I8IECI2W3YI38JSXOPMLP8.jpg\n", "[Batch 1] ✅ FINST-PJE66J91RJNZ1RSPBUYJB5ZF2PTI2TGY7PLGMAN.jpg\n", "[Batch 1] ✅ FINST-PQ5669911JFP4W356K5HS98S8MZC2MUHMO82MX5.png\n", "[Batch 1] ✅ FINST-PRF66GB105ZWQSK7CUNWR97ZV6LG3050I9UCMAY.png\n", "[Batch 1] ✅ FINST-QJG66FC1JCE085Q3N439VAMLKVFF3GUQFMOHMEF2.xlsx\n", "[Batch 1] ✅ FINST-QJG66IB1GWQZN4GVAGZCW8NQ61VB3AK3KSRGMWY1.xlsx\n", "[Batch 1] ✅ FINST-QKC666919BQY70PZ8G3T57AX7UNA29H3N0BFMSC.xlsx\n", "[Batch 1] ✅ FINST-QW8665B1XE41XSIJK01GJCNZ5YNQ2CRLVXNIMZW.png\n", "[Batch 1] ✅ FINST-RAC66GD197JYBI9Q9WU4B731F3O52QOQQ42FMFR5.jpg\n", "[Batch 1] ✅ FINST-UAD66591M1KJAXF6CROAFDK9Y4PD3IFY2QZTLUR1.jpg\n", "[Batch 1] ✅ FINST-UH9665D1TLYDLO5TDNPV0CEJTFGX2AMSWP4MLGP.png\n", "[Batch 1] ✅ FINST-USC66V6144XYJV79FR19G4JRKPA52X6OX8LFMWU3.xlsx\n", "[Batch 1] ✅ FINST-UZA66QC18I9WZM23F0GIC4UMA25B2C14SHUBM742.png\n", "[Batch 1] ✅ FINST-WM6666B10OZIDIA9C6K6R8A6NXEU3UON1HETL2ZJ.jpg\n", "[Batch 1] ✅ FINST-WSF66J812FUXCO5ZCWI70C2TW7TG2OMS0F2EMAP1.png\n", "[Batch 1] ✅ FINST-WSF66J818UYXDCKS8IZ7K50QAGNH2K3MJG8EMJP1.xlsx\n", "[Batch 1] ✅ FINST-WYG66T718EQ0Z4TMNO8P2CRTS6NE3EUF016IMSDA.pptx\n", "[Batch 1] ✅ FINST-Z6966NB14IDEWL268Y71A8FOS0HD2ROSG3QMLGZ3.mp4\n", "[Batch 1] ✅ FINST-ZH866O918DRFX8WWEBEDSBMRTNU93TRYXNNOLVY.jpg\n", "[Batch 1] ✅ FINST-ZKD66Q71XPBRGBVI8Z5FGCIWR2KS2NCI9TZ4MQ5L.xlsx\n", "📁 正在生成批次 2: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_2\n", "[Batch 2] ✅ FINST-0D866I81JANY5WG8A2DT15S63HZH20YFR68FMQJA.png\n", "[Batch 2] ✅ FINST-0HD66Z81DFXYBP816VRKD6S2HA2H3RYCBYKFMR6.jpg\n", "[Batch 2] ✅ FINST-54A66HC1426KP5L87MXEA682I67O23YKVXUUL9U9.jpg\n", "[Batch 2] ✅ FINST-65D66X71VHAPFNPZ9OFURCIREZAS28FI7P12MJS.jpg\n", "[Batch 2] ✅ FINST-9FA66WC1LDJNFROD7HJUI4OJ6C2J22UP25SZLUQA.jpg\n", "[Batch 2] ✅ FINST-BL866S61XU8DOZG5BZ6E4DZ2UOIV3B6CEHALL3QI.png\n", "[Batch 2] ✅ FINST-ETA66681ZAHDHL2OA0MQR6UB9W5N2MZM2DGLLU2.xlsx\n", "[Batch 2] ✅ FINST-HRD66W919462UFW0NG4PODHZZUW63074RZAKM1DK.png\n", "[Batch 2] ✅ FINST-IQC66GC18W4YQ8GSCL23T582HU1H3960PVGEML8.png\n", "[Batch 2] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "[Batch 2] ✅ FINST-J3D66LA13NTHEZAICABNRCD3KVCY222Q7IORL7UD.xlsx\n", "[Batch 2] ✅ FINST-K7E66Z91F5NYOC0UD20BO775JN8C3D763K6FM16.xlsx\n", "[Batch 2] ✅ FINST-KW866QB13VPZ5OSE9CE0LAWVKEO23QA4XVOGM92.jpg\n", "[Batch 2] ✅ FINST-LLA66D71DDUN56UUBRVZVD2EO3TS291ZDU00M734.png\n", "[Batch 2] ✅ FINST-NLD66NA171BT4QDDCKR6HBD8XSHG3UJ1FSP7MJ39.png\n", "[Batch 2] ✅ FINST-PF866EA1IKDECQEC8I8IECI2W3YI38JSXOPMLP8.jpg\n", "📁 正在生成批次 3: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_3\n", "[Batch 3] ✅ FINST-65D66X71VHAPFNPZ9OFURCIREZAS28FI7P12MJS.png\n", "[Batch 3] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "📁 正在生成批次 4: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_4\n", "[Batch 4] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "📁 正在生成批次 5: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_5\n", "[Batch 5] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "📁 正在生成批次 6: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_6\n", "[Batch 6] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "📁 正在生成批次 7: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_7\n", "[Batch 7] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "📁 正在生成批次 8: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_8\n", "[Batch 8] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "📁 正在生成批次 9: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_9\n", "[Batch 9] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n", "\n", "🎉 处理完成!共生成 9 个批次文件夹。\n" ] } ], "source": [ "import os\n", "import shutil\n", "import re\n", "import hashlib\n", "\n", "# 配置\n", "root_path = r\"C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\"\n", "\n", "# 存储:{finst_id: [file_path1, file_path2, ...]}\n", "instance_files = {}\n", "\n", "# Windows 非法字符\n", "ILLEGAL_CHARS = r'[<>:\"/\\\\|?*\\x00-\\x1f]'\n", "\n", "def extract_or_fallback_prefix(dirname):\n", " match = re.match(r'^(FINST-[A-Z0-9]{10,})', dirname)\n", " return match.group(1) if match else dirname\n", "\n", "def sanitize_filename_part(part):\n", " return re.sub(ILLEGAL_CHARS, '_', part)\n", "\n", "print(\"🔍 正在扫描所有文件...\")\n", "\n", "# 第一步:遍历并按 FINST-ID 分组\n", "for dirpath, dirnames, filenames in os.walk(root_path):\n", " rel_path = os.path.relpath(dirpath, root_path)\n", " if rel_path.startswith(\"输出_\"):\n", " continue\n", "\n", " parts = rel_path.split(os.sep)\n", " \n", " # 找到路径中第一个 FINST- 开头的目录\n", " finst_dirname = None\n", " for part in parts:\n", " if part.startswith(\"FINST-\"):\n", " finst_dirname = part\n", " break\n", " \n", " if finst_dirname is None:\n", " continue\n", "\n", " clean_prefix = extract_or_fallback_prefix(finst_dirname)\n", " safe_prefix = sanitize_filename_part(clean_prefix)\n", "\n", " for filename in filenames:\n", " src_file = os.path.join(dirpath, filename)\n", " instance_files.setdefault(safe_prefix, []).append(src_file)\n", "\n", "print(f\"✅ 共找到 {len(instance_files)} 个实例,总计 {sum(len(v) for v in instance_files.values())} 个文件\")\n", "\n", "# 第二步:按轮次分发到输出文件夹\n", "max_rounds = max(len(files) for files in instance_files.values()) if instance_files else 0\n", "\n", "for round_index in range(max_rounds):\n", " batch_index = round_index + 1\n", " output_dir = os.path.join(root_path, f\"输出_{batch_index}\")\n", " os.makedirs(output_dir, exist_ok=True)\n", " print(f\"📁 正在生成批次 {batch_index}: {output_dir}\")\n", "\n", " for finst_id, file_list in instance_files.items():\n", " if round_index < len(file_list):\n", " src_file = file_list[round_index]\n", " _, ext = os.path.splitext(src_file)\n", " safe_ext = sanitize_filename_part(ext)\n", " if safe_ext and not safe_ext.startswith('.'):\n", " safe_ext = '.' + safe_ext\n", "\n", " # 编号从 2 开始:第0个 → -2, 第1个 → -3, ...\n", " counter = round_index + 1\n", " target_name = f\"{finst_id}{safe_ext}\"\n", "\n", "\n", "\n", " dst_file = os.path.join(output_dir, target_name)\n", "\n", " try:\n", " shutil.copy2(src_file, dst_file)\n", " print(f\"[Batch {batch_index}] ✅ {target_name}\")\n", " except Exception as e:\n", " print(f\"[Batch {batch_index}] ❌ 复制失败: {e}\")\n", "\n", "print(f\"\\n🎉 处理完成!共生成 {max_rounds} 个批次文件夹。\")" ] }, { "cell_type": "markdown", "id": "3bf861d3", "metadata": {}, "source": [ "附件、图片\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "90309f69", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "🔍 正在扫描所有文件...\n", "✅ 共找到 9 个文件,分属:附件、图片、其他\n", "\n", "📦 处理类别: 附件 (共 1 批)\n", "[附件 Batch 1] ✅ FINST-56B66Q91XU6TMONCFZBLBCVK9MS03SSG3SI7MR1.pdf\n", "[附件 Batch 1] ✅ FINST-C98664A1A8XJTVAW9W0256C4AF5S2JIWPBIULNM3.pdf\n", "[附件 Batch 1] ✅ FINST-JZ766R91YWUW0FZ6CXRXSBAVXQ0J2ZOZEEOCMGA.pdf\n", "[附件 Batch 1] ✅ FINST-R3D664B1B7ZYYR569QITJB9VCZXT2B8WIUNFM4X2.xlsx\n", "[附件 Batch 1] ✅ FINST-RC966V713AMLLTHG8M1UBD6OK7EG3M3PWTYWLQYL.pdf\n", "[附件 Batch 1] ✅ FINST-SUC66KA1UDIL18KXAMFCK9PW64XN375YHFQWLLC.pdf\n", "[附件 Batch 1] ✅ FINST-TM966BD1Y9HK1YK1BFUOL9IO9TSI3WK4G6CVLS45.xlsx\n", "[附件 Batch 1] ✅ FINST-ZKD66Q719O2TZRLY5HZJNAFGJW2F2IE4JYC7M0F.jpg\n", "\n", "📦 处理类别: 图片 (共 1 批)\n", "[图片 Batch 1] ✅ FINST-SUC66KA1C5YJQ4NNAKAGHBOOPPFQ3QX7EJQULEKV1.jpg\n", "\n", "🎉 所有类别处理完成!\n" ] } ], "source": [ "import os\n", "import shutil\n", "import re\n", "import hashlib\n", "\n", "# 配置\n", "root_path = r\"C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\商机提交_20260209161647_resources_1\"\n", "\n", "# 分类存储:{\"附件\": {finst_id: [file1, file2, ...]}, \"图片\": {...}, \"其他\": {...}}\n", "categorized_files = {\n", " \"附件\": {},\n", " \"图片\": {},\n", " \"其他\": {}\n", "}\n", "\n", "# Windows 非法字符\n", "ILLEGAL_CHARS = r'[<>:\"/\\\\|?*\\x00-\\x1f]'\n", "\n", "def extract_or_fallback_prefix(dirname):\n", " match = re.match(r'^(FINST-[A-Z0-9]{10,})', dirname)\n", " return match.group(1) if match else dirname\n", "\n", "def sanitize_filename_part(part):\n", " return re.sub(ILLEGAL_CHARS, '_', part)\n", "\n", "print(\"🔍 正在扫描所有文件...\")\n", "\n", "# 第一步:遍历并按来源分类 + 按 FINST-ID 分组\n", "for dirpath, dirnames, filenames in os.walk(root_path):\n", " rel_path = os.path.relpath(dirpath, root_path)\n", " if rel_path.startswith(\"输出_\"):\n", " continue\n", "\n", " parts = rel_path.split(os.sep)\n", " \n", " # 找到第一个 FINST- 开头的目录\n", " finst_dirname = None\n", " for part in parts:\n", " if part.startswith(\"FINST-\"):\n", " finst_dirname = part\n", " break\n", " \n", " if finst_dirname is None:\n", " continue\n", "\n", " clean_prefix = extract_or_fallback_prefix(finst_dirname)\n", " safe_prefix = sanitize_filename_part(clean_prefix)\n", "\n", " # 判断当前路径相对于 FINST-xxx 的位置\n", " relative_to_finst = rel_path[len(finst_dirname):].lstrip(os.sep)\n", " source_type = \"其他\"\n", "\n", " if relative_to_finst == \"\" or not relative_to_finst:\n", " # 文件直接在 FINST-xxx 下\n", " source_type = \"其他\"\n", " elif relative_to_finst.startswith(\"附件\") or \"附件\" in relative_to_finst.split(os.sep):\n", " source_type = \"附件\"\n", " elif relative_to_finst.startswith(\"图片\") or \"图片\" in relative_to_finst.split(os.sep):\n", " source_type = \"图片\"\n", " else:\n", " source_type = \"其他\"\n", "\n", " for filename in filenames:\n", " src_file = os.path.join(dirpath, filename)\n", " categorized_files[source_type].setdefault(safe_prefix, []).append(src_file)\n", "\n", "# 统计\n", "total_files = sum(\n", " len(files) \n", " for category in categorized_files.values() \n", " for files in category.values()\n", ")\n", "print(f\"✅ 共找到 {total_files} 个文件,分属:附件、图片、其他\")\n", "\n", "# 第二步:对每种类别独立进行轮次分发\n", "for category_name, instance_dict in categorized_files.items():\n", " if not instance_dict:\n", " continue\n", "\n", " max_rounds = max(len(files) for files in instance_dict.values())\n", " print(f\"\\n📦 处理类别: {category_name} (共 {max_rounds} 批)\")\n", "\n", " for round_index in range(max_rounds):\n", " batch_index = round_index + 1\n", " output_dir = os.path.join(root_path, f\"输出_{category_name}_{batch_index}\")\n", " os.makedirs(output_dir, exist_ok=True)\n", "\n", " for finst_id, file_list in instance_dict.items():\n", " if round_index < len(file_list):\n", " src_file = file_list[round_index]\n", " _, ext = os.path.splitext(src_file)\n", " safe_ext = sanitize_filename_part(ext)\n", " if safe_ext and not safe_ext.startswith('.'):\n", " safe_ext = '.' + safe_ext\n", "\n", " # 文件名:FINST-XXX.ext (无任何后缀)\n", " target_name = f\"{finst_id}{safe_ext}\"\n", "\n", " # 防止过长\n", " if len(target_name) > 200:\n", " hash_part = hashlib.md5(finst_id.encode()).hexdigest()[:8]\n", " truncated = finst_id[:100] + \"_\" + hash_part\n", " target_name = f\"{truncated}{safe_ext}\"\n", "\n", " dst_file = os.path.join(output_dir, target_name)\n", "\n", " try:\n", " shutil.copy2(src_file, dst_file)\n", " print(f\"[{category_name} Batch {batch_index}] ✅ {target_name}\")\n", " except Exception as e:\n", " print(f\"[{category_name} Batch {batch_index}] ❌ 复制失败: {e}\")\n", "\n", "print(f\"\\n🎉 所有类别处理完成!\")" ] } ], "metadata": { "kernelspec": { "display_name": "F6+宜搭+其它", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.11" } }, "nbformat": 4, "nbformat_minor": 5 }