{"id":3741,"date":"2025-08-20T16:28:38","date_gmt":"2025-08-20T08:28:38","guid":{"rendered":"https:\/\/blog.kangyue.pro\/?p=3741"},"modified":"2026-01-07T15:04:05","modified_gmt":"2026-01-07T07:04:05","slug":"%e4%b8%80%e4%b8%aa%e9%94%ae%e5%85%a5%e5%a4%9a%e8%a1%8c%e8%b7%af%e5%be%84%e7%9a%84%e6%8b%b7%e8%b4%9d%e5%b7%a5%e5%85%b7%ef%bc%88python%ef%bc%89","status":"publish","type":"post","link":"https:\/\/blog.kangyue.pro\/?p=3741","title":{"rendered":"\u4e00\u4e2a\u952e\u5165\u591a\u884c\u8def\u5f84\u7684\u62f7\u8d1d\u5de5\u5177\uff08Python\uff09"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>\u4e00\u4e2aGUI\u5de5\u5177\uff0c\u5305\u62ec\u4e00\u4e2a\u6587\u672c\u6846\uff0c\u53ef\u4ee5\u628a\u4e00\u4e9b\u8def\u5f84\u7684\u6587\u4ef6\uff08\u4e00\u884c\u4e00\u4e2a\uff09\u62f7\u8d1d\u5230\u67d0\u76d8\uff08\u5982F\u76d8\uff09\uff0c\u6839\u636e\u8def\u5f84\u81ea\u52a8\u521b\u5efa\u76f8\u5e94\u6587\u4ef6\u5939\u3002<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">\u754c\u9762<\/h1>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"902\" height=\"632\" src=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/08\/image-26.png\" alt=\"\" class=\"wp-image-3745\" srcset=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/08\/image-26.png 902w, https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/08\/image-26-768x538.png 768w\" sizes=\"auto, (max-width: 902px) 100vw, 902px\" \/><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">\u4ecb\u7ecd<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u529f\u80fd\u7279\u70b9<\/strong>\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u53ef\u89c6\u5316\u4efb\u52a1\u7ba1\u7406<\/strong>\uff1a\u5c06\u6587\u4ef6\u8def\u5f84\u52a0\u8f7d\u5230\u8868\u683c\u4e2d\uff0c\u6bcf\u4e2a\u6587\u4ef6\u72b6\u6001\u4e00\u76ee\u4e86\u7136\uff08\u672a\u5f00\u59cb\u3001\u8fdb\u884c\u4e2d\u3001\u6210\u529f\u3001\u5931\u8d25\u3001\u8df3\u8fc7\uff09\u3002<\/li>\n\n\n\n<li><strong>\u667a\u80fd\u62f7\u8d1d<\/strong>\uff1a\u81ea\u52a8\u5224\u65ad\u76ee\u6807\u4f4d\u7f6e\u662f\u5426\u5df2\u5b58\u5728\u540c\u540d\u6587\u4ef6\u4e14\u5927\u5c0f\u4e00\u81f4\uff0c\u907f\u514d\u91cd\u590d\u62f7\u8d1d\u3002<\/li>\n\n\n\n<li><strong>\u8fdb\u5ea6\u663e\u793a<\/strong>\uff1a\u5e26\u8fdb\u5ea6\u6761\u548c\u767e\u5206\u6bd4\uff0c\u5b9e\u65f6\u663e\u793a\u62f7\u8d1d\u8fdb\u5ea6\u3002<\/li>\n\n\n\n<li><strong>\u6682\u505c\/\u7ee7\u7eed<\/strong>\uff1a\u652f\u6301\u62f7\u8d1d\u8fc7\u7a0b\u4e2d\u968f\u65f6\u6682\u505c\u6216\u7ee7\u7eed\uff0c\u64cd\u4f5c\u7075\u6d3b\u3002<\/li>\n\n\n\n<li><strong>\u4efb\u52a1\u6301\u4e45\u5316<\/strong>\uff1a\u81ea\u52a8\u4fdd\u5b58\u5f53\u524d\u4efb\u52a1\u5217\u8868\u548c\u72b6\u6001\uff0c\u4e0b\u6b21\u542f\u52a8\u53ef\u76f4\u63a5\u6062\u590d\uff0c\u65b9\u4fbf\u957f\u65f6\u95f4\u6216\u591a\u6279\u6b21\u62f7\u8d1d\u3002<\/li>\n\n\n\n<li><strong>\u7b80\u6d01\u6613\u7528<\/strong>\uff1a\u652f\u6301\u7c98\u8d34\u6587\u4ef6\u8def\u5f84\u6587\u672c\uff0c\u4e00\u952e\u52a0\u8f7d\u5e76\u5f00\u59cb\u62f7\u8d1d\uff0c\u9002\u5408\u6279\u91cf\u7ba1\u7406\u6587\u4ef6\u3002<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u9002\u7528\u573a\u666f<\/strong>\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u6279\u91cf\u62f7\u8d1d\u6587\u4ef6\u5230\u79fb\u52a8\u786c\u76d8\u3001U\u76d8\u6216\u5176\u4ed6\u76d8\u7b26<\/li>\n\n\n\n<li>\u5927\u91cf\u6587\u4ef6\u8fc1\u79fb\u6216\u5907\u4efd<\/li>\n\n\n\n<li>\u9700\u8981\u53ef\u89c6\u5316\u8ddf\u8e2a\u6bcf\u4e2a\u6587\u4ef6\u62f7\u8d1d\u72b6\u6001\u7684\u7528\u6237<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7f3a\u70b9\uff1a<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u9009\u4e2d\u7684\u884c\u80cc\u666f\u8272\u4e5f\u662f\u9ec4\u8272<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">py\u4ee3\u7801<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">2.0<\/h3>\n\n\n\t\t<div class='wp-block-bch-code-highlight  align' id='bhcCodeHighlight-da69bc36-c' data-attributes='{&quot;cId&quot;:&quot;da69bc36-c&quot;,&quot;language&quot;:&quot;python&quot;,&quot;code&quot;:&quot;import os\\nimport shutil\\nimport re\\nimport tkinter as tk\\nfrom tkinter import ttk, messagebox\\nimport threading\\nimport time\\nimport json\\nfrom datetime import timedelta\\n\\n# ----------------\\u5168\\u5c40\\u53d8\\u91cf----------------\\ncopying = False\\npaused = False\\nfile_list = []\\nstart_time = None\\nTASK_FILE = os.path.join(os.path.dirname(__file__), \\&quot;tasks.json\\&quot;)\\n\\n# ----------------\\u529f\\u80fd\\u51fd\\u6570----------------\\ndef extract_paths(text):\\n    \\&quot;\\&quot;\\&quot;\\u63d0\\u53d6 Windows \\u6587\\u4ef6\\u8def\\u5f84\\&quot;\\&quot;\\&quot;\\n    pattern = r\\&quot;[A-Z]:\\\\\\\\[^\\\\n\\\\r]+\\&quot;\\n    return re.findall(pattern, text)\\n\\ndef save_tasks():\\n    \\&quot;\\&quot;\\&quot;\\u4fdd\\u5b58\\u5f53\\u524d\\u4efb\\u52a1\\u5217\\u8868\\u5230 JSON\\&quot;\\&quot;\\&quot;\\n    tasks = [{\\&quot;path\\&quot;: f[\\&quot;path\\&quot;], \\&quot;status\\&quot;: tree.item(f[\\&quot;iid\\&quot;])[\\&quot;values\\&quot;][1]} for f in file_list]\\n    try:\\n        with open(TASK_FILE, \\&quot;w\\&quot;, encoding=\\&quot;utf-8\\&quot;) as f:\\n            json.dump(tasks, f, ensure_ascii=False, indent=2)\\n    except Exception as e:\\n        print(\\&quot;\\u4fdd\\u5b58\\u4efb\\u52a1\\u5931\\u8d25:\\&quot;, e)\\n\\ndef load_tasks_from_file():\\n    \\&quot;\\&quot;\\&quot;\\u4ece JSON \\u6587\\u4ef6\\u52a0\\u8f7d\\u4efb\\u52a1\\u5217\\u8868\\&quot;\\&quot;\\&quot;\\n    global file_list\\n    if not os.path.exists(TASK_FILE):\\n        return\\n\\n    try:\\n        with open(TASK_FILE, \\&quot;r\\&quot;, encoding=\\&quot;utf-8\\&quot;) as f:\\n            tasks = json.load(f)\\n    except (json.JSONDecodeError, FileNotFoundError):\\n        return\\n\\n    file_list = []\\n    tree.delete(*tree.get_children())\\n    for idx, t in enumerate(tasks):\\n        iid = f\\&quot;file_{idx}\\&quot;\\n        status = t.get(\\&quot;status\\&quot;, \\&quot;\\u672a\\u5f00\\u59cb\\&quot;)\\n        tag = {\\n            \\&quot;\\u672a\\u5f00\\u59cb\\&quot;: \\&quot;pending\\&quot;,\\n            \\&quot;\\u6210\\u529f\\&quot;: \\&quot;success\\&quot;,\\n            \\&quot;\\u5931\\u8d25\\&quot;: \\&quot;fail\\&quot;,\\n            \\&quot;\\u8df3\\u8fc7\\&quot;: \\&quot;skipped\\&quot;,\\n            \\&quot;\\u8fdb\\u884c\\u4e2d\\&quot;: \\&quot;running\\&quot;\\n        }.get(status, \\&quot;pending\\&quot;)\\n        tree.insert(\\&quot;\\&quot;, \\&quot;end\\&quot;, iid=iid, values=(t[\\&quot;path\\&quot;], status), tags=(tag,))\\n        file_list.append({\\&quot;path\\&quot;: t[\\&quot;path\\&quot;], \\&quot;iid\\&quot;: iid})\\n    update_status_counts()\\n\\ndef start_copy_thread():\\n    \\&quot;\\&quot;\\&quot;\\u5f00\\u542f\\u7ebf\\u7a0b\\u6267\\u884c\\u62f7\\u8d1d\\uff0c\\u907f\\u514d\\u963b\\u585e GUI\\&quot;\\&quot;\\&quot;\\n    global copying, start_time\\n    if copying:\\n        return\\n    copying = True\\n    start_time = time.time()\\n    threading.Thread(target=run_copy, daemon=True).start()\\n\\ndef toggle_pause():\\n    \\&quot;\\&quot;\\&quot;\\u6682\\u505c\\\/\\u7ee7\\u7eed\\&quot;\\&quot;\\&quot;\\n    global paused\\n    paused = not paused\\n    pause_button.config(text=\\&quot;\\u7ee7\\u7eed\\&quot; if paused else \\&quot;\\u6682\\u505c\\&quot;)\\n\\ndef update_status_counts():\\n    \\&quot;\\&quot;\\&quot;\\u66f4\\u65b0\\u72b6\\u6001\\u8ba1\\u6570\\&quot;\\&quot;\\&quot;\\n    pending = sum(1 for f in file_list if tree.item(f[\\&quot;iid\\&quot;])[\\&quot;values\\&quot;][1] == \\&quot;\\u672a\\u5f00\\u59cb\\&quot;)\\n    success = sum(1 for f in file_list if tree.item(f[\\&quot;iid\\&quot;])[\\&quot;values\\&quot;][1] == \\&quot;\\u6210\\u529f\\&quot;)\\n    failed = sum(1 for f in file_list if tree.item(f[\\&quot;iid\\&quot;])[\\&quot;values\\&quot;][1] == \\&quot;\\u5931\\u8d25\\&quot;)\\n    status_label_var.set(f\\&quot;\\u5f85\\u5904\\u7406: {pending}  \\u6210\\u529f: {success}  \\u5931\\u8d25: {failed}\\&quot;)\\n\\ndef format_time(seconds):\\n    \\&quot;\\&quot;\\&quot;\\u683c\\u5f0f\\u5316\\u65f6\\u95f4\\u4e3a hh:mm:ss\\&quot;\\&quot;\\&quot;\\n    return str(timedelta(seconds=int(seconds)))\\n\\ndef check_text_box():\\n    \\&quot;\\&quot;\\&quot;\\u68c0\\u67e5\\u6587\\u672c\\u6846\\u662f\\u5426\\u4e3a\\u7a7a\\u5e76\\u66f4\\u65b0\\u52a0\\u8f7d\\u6309\\u94ae\\u72b6\\u6001\\&quot;\\&quot;\\&quot;\\n    text = text_box.get(\\&quot;1.0\\&quot;, tk.END).strip()\\n    load_button.config(state=\\&quot;normal\\&quot; if text else \\&quot;disabled\\&quot;)\\n\\ndef run_copy():\\n    global copying, paused, start_time\\n    dest_drive = drive_var.get().strip().upper()\\n    if not re.fullmatch(r\\&quot;[A-Z]\\&quot;, dest_drive):\\n        messagebox.showerror(\\&quot;\\u9519\\u8bef\\&quot;, \\&quot;\\u8bf7\\u8f93\\u5165\\u6709\\u6548\\u7684\\u76ee\\u6807\\u76d8\\u7b26\\uff08\\u5982 F\\uff09\\&quot;)\\n        copying = False\\n        return\\n\\n    total = len(file_list)\\n    for idx, file_info in enumerate(file_list):\\n        while paused:\\n            time.sleep(0.1)\\n\\n        path = file_info[\\&quot;path\\&quot;]\\n        tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;running\\&quot;,))\\n        tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u8fdb\\u884c\\u4e2d\\&quot;)\\n        root.update_idletasks()\\n        save_tasks()\\n\\n        if os.path.isfile(path):\\n            rel_path = os.path.splitdrive(path)[1].lstrip(\\&quot;\\\\\\\\\\\/\\&quot;)\\n            dest_path = os.path.join(dest_drive + \\&quot;:\\\\\\\\\\&quot;, rel_path)\\n            os.makedirs(os.path.dirname(dest_path), exist_ok=True)\\n            try:\\n                if os.path.exists(dest_path) and os.path.getsize(dest_path) == os.path.getsize(path):\\n                    tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;skipped\\&quot;,))\\n                    tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u8df3\\u8fc7\\&quot;)\\n                else:\\n                    shutil.copy2(path, dest_path)\\n                    tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;success\\&quot;,))\\n                    tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u6210\\u529f\\&quot;)\\n            except Exception as e:\\n                tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;fail\\&quot;,))\\n                tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u5931\\u8d25\\&quot;)\\n        else:\\n            tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;fail\\&quot;,))\\n            tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u5931\\u8d25\\&quot;)\\n\\n        # \\u66f4\\u65b0\\u8fdb\\u5ea6\\u548c\\u65f6\\u95f4\\n        progress = (idx + 1) \\\/ total * 100\\n        progress_var.set(progress)\\n        elapsed = time.time() - start_time\\n        remaining = (elapsed \\\/ (idx + 1) * (total - idx - 1)) if idx + 1 &lt; total else 0\\n        progress_label_var.set(f\\&quot;{idx + 1}\\\/{total} ({progress:.1f}%)  \\u5df2\\u7528: {format_time(elapsed)}  \\u5269\\u4f59: {format_time(remaining)}\\&quot;)\\n        update_status_counts()\\n        root.update_idletasks()\\n        save_tasks()\\n\\n    copying = False\\n    messagebox.showinfo(\\&quot;\\u5b8c\\u6210\\&quot;, \\&quot;\\u6587\\u4ef6\\u62f7\\u8d1d\\u5b8c\\u6210\\uff01\\&quot;)\\n    save_tasks()\\n\\ndef load_paths():\\n    \\&quot;\\&quot;\\&quot;\\u89e3\\u6790\\u6587\\u672c\\u6846\\u8def\\u5f84\\u5e76\\u586b\\u5145\\u8868\\u683c\\&quot;\\&quot;\\&quot;\\n    global file_list\\n    text = text_box.get(\\&quot;1.0\\&quot;, tk.END)\\n    paths = extract_paths(text)\\n    file_list = []\\n    tree.delete(*tree.get_children())\\n    for idx, path in enumerate(paths):\\n        iid = f\\&quot;file_{idx}\\&quot;\\n        tree.insert(\\&quot;\\&quot;, \\&quot;end\\&quot;, iid=iid, values=(path, \\&quot;\\u672a\\u5f00\\u59cb\\&quot;), tags=(\\&quot;pending\\&quot;,))\\n        file_list.append({\\&quot;path\\&quot;: path, \\&quot;iid\\&quot;: iid})\\n    save_tasks()\\n    update_status_counts()\\n\\ndef darken_color(hex_color, factor=0.8):\\n    \\&quot;\\&quot;\\&quot;\\u5c06\\u989c\\u8272\\u52a0\\u6df1\\&quot;\\&quot;\\&quot;\\n    hex_color = hex_color.lstrip(&#039;#&#039;)\\n    rgb = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))\\n    rgb = tuple(max(0, int(c * factor)) for c in rgb)\\n    return f&#039;#{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}&#039;\\n\\n# ---------------- GUI ----------------\\nroot = tk.Tk()\\nroot.title(\\&quot;\\u6587\\u4ef6\\u62f7\\u8d1d\\u5de5\\u5177\\uff08\\u53ef\\u89c6\\u5316\\u8868\\u683c\\u7248\\uff09\\&quot;)\\nroot.geometry(\\&quot;900x600\\&quot;)\\n\\n# \\u54cd\\u5e94\\u7a97\\u53e3\\u5927\\u5c0f\\u53d8\\u5316\\ndef on_resize(event):\\n    width = root.winfo_width() - 30\\n    text_box.config(width=max(50, width \\\/\\\/ 10))\\n    tree.column(\\&quot;\\u8def\\u5f84\\&quot;, width=int(width * 0.85))\\n    tree.column(\\&quot;\\u72b6\\u6001\\&quot;, width=int(width * 0.15))\\n    progress_bar.config(length=width)\\n\\nroot.bind(&#039;&lt;Configure&gt;&#039;, on_resize)\\n\\n# \\u4e3b\\u6846\\u67b6\\uff0c\\u4f7f\\u7528 paned window \\u5b9e\\u73b0\\u53ef\\u8c03\\u6574\\u5e03\\u5c40\\nmain_pane = ttk.PanedWindow(root, orient=tk.VERTICAL)\\nmain_pane.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)\\n\\n# \\u4e0a\\u90e8\\u6846\\u67b6\\uff08\\u6587\\u672c\\u8f93\\u5165\\u548c\\u63a7\\u5236\\u6309\\u94ae\\uff09\\ntop_frame = ttk.Frame(main_pane)\\nmain_pane.add(top_frame, weight=1)\\n\\n# \\u6587\\u672c\\u8f93\\u5165\\ntk.Label(top_frame, text=\\&quot;\\u8f93\\u5165\\u5305\\u542b\\u8def\\u5f84\\u7684\\u6587\\u672c\\uff1a\\&quot;).pack(anchor=\\&quot;w\\&quot;, padx=5, pady=5)\\ntext_box = tk.Text(top_frame, height=5, width=110)\\ntext_box.pack(fill=tk.X, padx=5, pady=5)\\ntext_box.bind(&#039;&lt;KeyRelease&gt;&#039;, lambda e: check_text_box())\\n\\n# \\u76ee\\u6807\\u76d8\\u7b26\\u548c\\u6309\\u94ae\\ncontrol_frame = ttk.Frame(top_frame)\\ncontrol_frame.pack(fill=tk.X, padx=5, pady=5)\\ntk.Label(control_frame, text=\\&quot;\\u76ee\\u6807\\u76d8\\u7b26\\uff1a\\&quot;).pack(side=\\&quot;left\\&quot;)\\ndrive_var = tk.StringVar()\\ndrive_entry = tk.Entry(control_frame, textvariable=drive_var, width=5)\\ndrive_entry.pack(side=\\&quot;left\\&quot;, padx=5)\\nload_button = tk.Button(control_frame, text=\\&quot;\\u52a0\\u8f7d\\u8def\\u5f84\\&quot;, command=load_paths, bg=\\&quot;#2196F3\\&quot;, fg=\\&quot;white\\&quot;)\\nload_button.pack(side=\\&quot;left\\&quot;, padx=5)\\nload_button.config(state=\\&quot;disabled\\&quot;)\\nstart_button = tk.Button(control_frame, text=\\&quot;\\u5f00\\u59cb\\u62f7\\u8d1d\\&quot;, command=start_copy_thread, bg=\\&quot;#4CAF50\\&quot;, fg=\\&quot;white\\&quot;)\\nstart_button.pack(side=\\&quot;left\\&quot;, padx=5)\\npause_button = tk.Button(control_frame, text=\\&quot;\\u6682\\u505c\\&quot;, command=toggle_pause, bg=\\&quot;#FFC107\\&quot;)\\npause_button.pack(side=\\&quot;left\\&quot;, padx=5)\\n\\n# \\u8fdb\\u5ea6\\u548c\\u72b6\\u6001\\nstatus_frame = ttk.Frame(top_frame)\\nstatus_frame.pack(fill=tk.X, padx=5, pady=2)\\ntk.Label(status_frame, text=\\&quot;\\u8fdb\\u5ea6\\uff1a\\&quot;).pack(anchor=\\&quot;w\\&quot;)\\nprogress_var = tk.DoubleVar()\\nprogress_bar = ttk.Progressbar(status_frame, variable=progress_var, maximum=100)\\nprogress_bar.pack(fill=tk.X, pady=2)\\nprogress_label_var = tk.StringVar()\\nprogress_label_var.set(\\&quot;0\\\/0 (0%)\\&quot;)\\nprogress_label = tk.Label(status_frame, textvariable=progress_label_var)\\nprogress_label.pack(anchor=\\&quot;w\\&quot;)\\nstatus_label_var = tk.StringVar()\\nstatus_label_var.set(\\&quot;\\u5f85\\u5904\\u7406: 0  \\u6210\\u529f: 0  \\u5931\\u8d25: 0\\&quot;)\\nstatus_label = tk.Label(status_frame, textvariable=status_label_var)\\nstatus_label.pack(anchor=\\&quot;w\\&quot;)\\n\\n# \\u8868\\u683c\\u663e\\u793a\\ntree_frame = ttk.Frame(main_pane)\\nmain_pane.add(tree_frame, weight=3)\\ncolumns = (\\&quot;\\u8def\\u5f84\\&quot;, \\&quot;\\u72b6\\u6001\\&quot;)\\ntree = ttk.Treeview(tree_frame, columns=columns, show=\\&quot;headings\\&quot;)\\ntree.heading(\\&quot;\\u8def\\u5f84\\&quot;, text=\\&quot;\\u6587\\u4ef6\\u8def\\u5f84\\&quot;)\\ntree.heading(\\&quot;\\u72b6\\u6001\\&quot;, text=\\&quot;\\u72b6\\u6001\\&quot;)\\ntree_scroll = ttk.Scrollbar(tree_frame, orient=\\&quot;vertical\\&quot;, command=tree.yview)\\ntree.configure(yscrollcommand=tree_scroll.set)\\ntree.pack(side=\\&quot;left\\&quot;, fill=tk.BOTH, expand=True)\\ntree_scroll.pack(side=\\&quot;right\\&quot;, fill=\\&quot;y\\&quot;)\\n\\n# ----------------\\u6837\\u5f0f\\u989c\\u8272----------------\\nstyle = ttk.Style()\\nstyle.theme_use(\\&quot;default\\&quot;)\\ncolors = {\\n    \\&quot;pending\\&quot;: \\&quot;#FFFFFF\\&quot;,\\n    \\&quot;running\\&quot;: \\&quot;#FFFF66\\&quot;,\\n    \\&quot;success\\&quot;: \\&quot;#A0FFA0\\&quot;,\\n    \\&quot;fail\\&quot;: \\&quot;#FFA0A0\\&quot;,\\n    \\&quot;skipped\\&quot;: \\&quot;#D0D0D0\\&quot;\\n}\\nstyle.configure(\\&quot;Treeview\\&quot;, rowheight=25)\\nfor tag, color in colors.items():\\n    tree.tag_configure(tag, background=color)\\n    style.configure(f\\&quot;{tag}.Treeview\\&quot;, background=color)\\n    style.map(f\\&quot;{tag}.Treeview\\&quot;,\\n              background=[(\\&quot;selected\\&quot;, darken_color(color))],\\n              foreground=[(\\&quot;selected\\&quot;, \\&quot;black\\&quot;)])\\n\\n# \\u72b6\\u6001\\u8ba1\\u6570\\u989c\\u8272\\ndef update_status_colors():\\n    pending_text = status_label_var.get().split(\\&quot;  \\&quot;)[0]\\n    success_text = status_label_var.get().split(\\&quot;  \\&quot;)[1]\\n    failed_text = status_label_var.get().split(\\&quot;  \\&quot;)[2]\\n    status_label.configure(text=f\\&quot;{pending_text}  {success_text}  {failed_text}\\&quot;,\\n                          foreground=\\&quot;black\\&quot;)\\n\\nstatus_label_var.trace_add(\\&quot;write\\&quot;, lambda *args: update_status_colors())\\n\\n# ----------------\\u542f\\u52a8\\u65f6\\u52a0\\u8f7d\\u4e0a\\u6b21\\u4efb\\u52a1----------------\\nload_tasks_from_file()\\ncheck_text_box()\\n\\nroot.mainloop()&quot;,&quot;codeTypo&quot;:{&quot;desktop&quot;:10,&quot;tablet&quot;:15,&quot;mobile&quot;:14},&quot;width&quot;:{&quot;desktop&quot;:&quot;100%&quot;,&quot;tablet&quot;:&quot;101.7%&quot;,&quot;mobile&quot;:&quot;100%&quot;},&quot;height&quot;:{&quot;desktop&quot;:&quot;299px&quot;,&quot;tablet&quot;:&quot;0px&quot;,&quot;mobile&quot;:&quot;0px&quot;},&quot;align&quot;:&quot;&quot;,&quot;lineNumbers&quot;:true,&quot;theme&quot;:&quot;default&quot;,&quot;clipBoard&quot;:true,&quot;wordWrap&quot;:true,&quot;padding&quot;:{&quot;top&quot;:&quot;0px&quot;,&quot;right&quot;:&quot;0px&quot;,&quot;bottom&quot;:&quot;0px&quot;,&quot;left&quot;:&quot;0px&quot;},&quot;background&quot;:{&quot;color&quot;:&quot;#d3cfcf42&quot;},&quot;layout&quot;:{&quot;align&quot;:&quot;left&quot;},&quot;border&quot;:{&quot;color&quot;:&quot;#000&quot;,&quot;style&quot;:&quot;solid&quot;,&quot;width&quot;:&quot;0px&quot;},&quot;shadow&quot;:[],&quot;alignment&quot;:&quot;center&quot;,&quot;clipBoardColors&quot;:{&quot;color&quot;:&quot;#fff&quot;,&quot;bg&quot;:&quot;#00000024&quot;}}'><\/div>\r\n\r\n\t\t\n\n\n<h3 class=\"wp-block-heading\">1.0<\/h3>\n\n\n\t\t<div class='wp-block-bch-code-highlight  align' id='bhcCodeHighlight-12b37f3a-4' data-attributes='{&quot;cId&quot;:&quot;12b37f3a-4&quot;,&quot;language&quot;:&quot;python&quot;,&quot;code&quot;:&quot;import os\\nimport shutil\\nimport re\\nimport tkinter as tk\\nfrom tkinter import ttk, messagebox\\nimport threading\\nimport time\\nimport json\\n\\n# ----------------\\u5168\\u5c40\\u53d8\\u91cf----------------\\ncopying = False  # \\u662f\\u5426\\u6b63\\u5728\\u62f7\\u8d1d\\npaused = False   # \\u6682\\u505c\\u72b6\\u6001\\nfile_list = []   # \\u4efb\\u52a1\\u5217\\u8868\\n# \\u4f7f\\u7528\\u811a\\u672c\\u6240\\u5728\\u76ee\\u5f55\\u4fdd\\u5b58 JSON \\u6587\\u4ef6\\uff0c\\u4fdd\\u8bc1\\u65e0\\u8bba\\u4ece\\u54ea\\u91cc\\u8fd0\\u884c\\u90fd\\u80fd\\u6b63\\u786e\\u8bfb\\u53d6\\nTASK_FILE = os.path.join(os.path.dirname(__file__), \\&quot;tasks.json\\&quot;)\\n\\n# ----------------\\u529f\\u80fd\\u51fd\\u6570----------------\\ndef extract_paths(text):\\n    \\&quot;\\&quot;\\&quot;\\u63d0\\u53d6 Windows \\u6587\\u4ef6\\u8def\\u5f84\\&quot;\\&quot;\\&quot;\\n    pattern = r\\&quot;[A-Z]:\\\\\\\\[^\\\\n\\\\r]+\\&quot;\\n    return re.findall(pattern, text)\\n\\ndef save_tasks():\\n    \\&quot;\\&quot;\\&quot;\\u4fdd\\u5b58\\u5f53\\u524d\\u4efb\\u52a1\\u5217\\u8868\\u5230 JSON\\&quot;\\&quot;\\&quot;\\n    tasks = [{\\&quot;path\\&quot;: f[\\&quot;path\\&quot;], \\&quot;status\\&quot;: tree.item(f[\\&quot;iid\\&quot;])[\\&quot;values\\&quot;][1]} for f in file_list]\\n    try:\\n        with open(TASK_FILE, \\&quot;w\\&quot;, encoding=\\&quot;utf-8\\&quot;) as f:\\n            json.dump(tasks, f, ensure_ascii=False, indent=2)\\n    except Exception as e:\\n        print(\\&quot;\\u4fdd\\u5b58\\u4efb\\u52a1\\u5931\\u8d25:\\&quot;, e)\\n\\ndef load_tasks_from_file():\\n    \\&quot;\\&quot;\\&quot;\\u4ece JSON \\u6587\\u4ef6\\u52a0\\u8f7d\\u4efb\\u52a1\\u5217\\u8868\\&quot;\\&quot;\\&quot;\\n    global file_list\\n    if not os.path.exists(TASK_FILE):\\n        return\\n\\n    try:\\n        with open(TASK_FILE, \\&quot;r\\&quot;, encoding=\\&quot;utf-8\\&quot;) as f:\\n            tasks = json.load(f)\\n    except (json.JSONDecodeError, FileNotFoundError):\\n        return\\n\\n    file_list = []\\n    tree.delete(*tree.get_children())\\n    for idx, t in enumerate(tasks):\\n        iid = f\\&quot;file_{idx}\\&quot;\\n        status = t.get(\\&quot;status\\&quot;, \\&quot;\\u672a\\u5f00\\u59cb\\&quot;)\\n        tag = {\\n            \\&quot;\\u672a\\u5f00\\u59cb\\&quot;: \\&quot;pending\\&quot;,\\n            \\&quot;\\u6210\\u529f\\&quot;: \\&quot;success\\&quot;,\\n            \\&quot;\\u5931\\u8d25\\&quot;: \\&quot;fail\\&quot;,\\n            \\&quot;\\u8df3\\u8fc7\\&quot;: \\&quot;skipped\\&quot;,\\n            \\&quot;\\u8fdb\\u884c\\u4e2d\\&quot;: \\&quot;running\\&quot;\\n        }.get(status, \\&quot;pending\\&quot;)\\n        tree.insert(\\&quot;\\&quot;, \\&quot;end\\&quot;, iid=iid, values=(t[\\&quot;path\\&quot;], status), tags=(tag,))\\n        file_list.append({\\&quot;path\\&quot;: t[\\&quot;path\\&quot;], \\&quot;iid\\&quot;: iid})\\n\\ndef start_copy_thread():\\n    \\&quot;\\&quot;\\&quot;\\u5f00\\u542f\\u7ebf\\u7a0b\\u6267\\u884c\\u62f7\\u8d1d\\uff0c\\u907f\\u514d\\u963b\\u585e GUI\\&quot;\\&quot;\\&quot;\\n    global copying\\n    if copying:\\n        return\\n    copying = True\\n    threading.Thread(target=run_copy, daemon=True).start()\\n\\ndef toggle_pause():\\n    \\&quot;\\&quot;\\&quot;\\u6682\\u505c\\\/\\u7ee7\\u7eed\\&quot;\\&quot;\\&quot;\\n    global paused\\n    paused = not paused\\n    pause_button.config(text=\\&quot;\\u7ee7\\u7eed\\&quot; if paused else \\&quot;\\u6682\\u505c\\&quot;)\\n\\ndef run_copy():\\n    global copying, paused\\n    dest_drive = drive_var.get().strip().upper()\\n    if not re.fullmatch(r\\&quot;[A-Z]\\&quot;, dest_drive):\\n        messagebox.showerror(\\&quot;\\u9519\\u8bef\\&quot;, \\&quot;\\u8bf7\\u8f93\\u5165\\u6709\\u6548\\u7684\\u76ee\\u6807\\u76d8\\u7b26\\uff08\\u5982 F\\uff09\\&quot;)\\n        copying = False\\n        return\\n\\n    total = len(file_list)\\n    for idx, file_info in enumerate(file_list):\\n        while paused:\\n            time.sleep(0.1)  # \\u6682\\u505c\\u5faa\\u73af\\n\\n        path = file_info[\\&quot;path\\&quot;]\\n        tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;running\\&quot;,))\\n        tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u8fdb\\u884c\\u4e2d\\&quot;)\\n        root.update_idletasks()\\n        save_tasks()\\n\\n        if os.path.isfile(path):\\n            rel_path = os.path.splitdrive(path)[1].lstrip(\\&quot;\\\\\\\\\\\/\\&quot;)\\n            dest_path = os.path.join(dest_drive + \\&quot;:\\\\\\\\\\&quot;, rel_path)\\n            os.makedirs(os.path.dirname(dest_path), exist_ok=True)\\n            try:\\n                if os.path.exists(dest_path) and os.path.getsize(dest_path) == os.path.getsize(path):\\n                    tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;skipped\\&quot;,))\\n                    tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u8df3\\u8fc7\\&quot;)\\n                else:\\n                    shutil.copy2(path, dest_path)\\n                    tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;success\\&quot;,))\\n                    tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u6210\\u529f\\&quot;)\\n            except Exception as e:\\n                tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;fail\\&quot;,))\\n                tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u5931\\u8d25\\&quot;)\\n        else:\\n            tree.item(file_info[\\&quot;iid\\&quot;], tags=(\\&quot;fail\\&quot;,))\\n            tree.set(file_info[\\&quot;iid\\&quot;], column=\\&quot;\\u72b6\\u6001\\&quot;, value=\\&quot;\\u5931\\u8d25\\&quot;)\\n\\n        progress_var.set((idx + 1) \\\/ total * 100)\\n        progress_label_var.set(f\\&quot;{idx + 1}\\\/{total} ({progress_var.get():.1f}%)\\&quot;)\\n        root.update_idletasks()\\n        save_tasks()\\n\\n    copying = False\\n    messagebox.showinfo(\\&quot;\\u5b8c\\u6210\\&quot;, \\&quot;\\u6587\\u4ef6\\u62f7\\u8d1d\\u5b8c\\u6210\\uff01\\&quot;)\\n    save_tasks()\\n\\ndef load_paths():\\n    \\&quot;\\&quot;\\&quot;\\u89e3\\u6790\\u6587\\u672c\\u6846\\u8def\\u5f84\\u5e76\\u586b\\u5145\\u8868\\u683c\\&quot;\\&quot;\\&quot;\\n    global file_list\\n    text = text_box.get(\\&quot;1.0\\&quot;, tk.END)\\n    paths = extract_paths(text)\\n    file_list = []\\n    tree.delete(*tree.get_children())\\n    for idx, path in enumerate(paths):\\n        iid = f\\&quot;file_{idx}\\&quot;\\n        tree.insert(\\&quot;\\&quot;, \\&quot;end\\&quot;, iid=iid, values=(path, \\&quot;\\u672a\\u5f00\\u59cb\\&quot;), tags=(\\&quot;pending\\&quot;,))\\n        file_list.append({\\&quot;path\\&quot;: path, \\&quot;iid\\&quot;: iid})\\n    save_tasks()\\n\\n# ---------------- GUI ----------------\\nroot = tk.Tk()\\nroot.title(\\&quot;\\u6587\\u4ef6\\u62f7\\u8d1d\\u5de5\\u5177\\uff08\\u53ef\\u89c6\\u5316\\u8868\\u683c\\u7248\\uff09\\&quot;)\\nroot.geometry(\\&quot;900x600\\&quot;)\\n\\n# \\u6587\\u672c\\u8f93\\u5165\\ntk.Label(root, text=\\&quot;\\u8f93\\u5165\\u5305\\u542b\\u8def\\u5f84\\u7684\\u6587\\u672c\\uff1a\\&quot;).pack(anchor=\\&quot;w\\&quot;, padx=10, pady=5)\\ntext_box = tk.Text(root, height=10, width=110)\\ntext_box.pack(padx=10, pady=5)\\n\\n# \\u76ee\\u6807\\u76d8\\u7b26\\nframe = tk.Frame(root)\\nframe.pack(anchor=\\&quot;w\\&quot;, padx=10, pady=5)\\ntk.Label(frame, text=\\&quot;\\u76ee\\u6807\\u76d8\\u7b26\\uff1a\\&quot;).pack(side=\\&quot;left\\&quot;)\\ndrive_var = tk.StringVar()\\ndrive_entry = tk.Entry(frame, textvariable=drive_var, width=5)\\ndrive_entry.pack(side=\\&quot;left\\&quot;, padx=5)\\ntk.Button(frame, text=\\&quot;\\u52a0\\u8f7d\\u8def\\u5f84\\&quot;, command=load_paths, bg=\\&quot;#2196F3\\&quot;, fg=\\&quot;white\\&quot;).pack(side=\\&quot;left\\&quot;, padx=5)\\nstart_button = tk.Button(frame, text=\\&quot;\\u5f00\\u59cb\\u62f7\\u8d1d\\&quot;, command=start_copy_thread, bg=\\&quot;#4CAF50\\&quot;, fg=\\&quot;white\\&quot;)\\nstart_button.pack(side=\\&quot;left\\&quot;, padx=5)\\npause_button = tk.Button(frame, text=\\&quot;\\u6682\\u505c\\&quot;, command=toggle_pause, bg=\\&quot;#FFC107\\&quot;)\\npause_button.pack(side=\\&quot;left\\&quot;, padx=5)\\n\\n# \\u8fdb\\u5ea6\\u6761\\ntk.Label(root, text=\\&quot;\\u8fdb\\u5ea6\\uff1a\\&quot;).pack(anchor=\\&quot;w\\&quot;, padx=10)\\nprogress_var = tk.DoubleVar()\\nprogress_bar = ttk.Progressbar(root, variable=progress_var, maximum=100, length=800)\\nprogress_bar.pack(padx=10, pady=2)\\nprogress_label_var = tk.StringVar()\\nprogress_label_var.set(\\&quot;0\\\/0 (0%)\\&quot;)\\nprogress_label = tk.Label(root, textvariable=progress_label_var)\\nprogress_label.pack(anchor=\\&quot;w\\&quot;, padx=10)\\n\\n# \\u8868\\u683c\\u663e\\u793a\\ncolumns = (\\&quot;\\u8def\\u5f84\\&quot;, \\&quot;\\u72b6\\u6001\\&quot;)\\ntree = ttk.Treeview(root, columns=columns, show=\\&quot;headings\\&quot;, height=15)\\ntree.heading(\\&quot;\\u8def\\u5f84\\&quot;, text=\\&quot;\\u6587\\u4ef6\\u8def\\u5f84\\&quot;)\\ntree.heading(\\&quot;\\u72b6\\u6001\\&quot;, text=\\&quot;\\u72b6\\u6001\\&quot;)\\ntree.column(\\&quot;\\u8def\\u5f84\\&quot;, width=700)\\ntree.column(\\&quot;\\u72b6\\u6001\\&quot;, width=100)\\ntree.pack(padx=10, pady=5)\\n\\n# ----------------\\u6837\\u5f0f\\u989c\\u8272----------------\\nstyle = ttk.Style()\\nstyle.theme_use(\\&quot;default\\&quot;)  # \\u4f7f\\u7528\\u9ed8\\u8ba4\\u4e3b\\u9898\\uff0c\\u5426\\u5219\\u67d0\\u4e9b\\u7cfb\\u7edf\\u4e3b\\u9898\\u4f1a\\u8986\\u76d6\\u989c\\u8272\\nstyle.map(\\&quot;Treeview\\&quot;,\\n          background=[(\\&quot;selected\\&quot;, \\&quot;#FFFF66\\&quot;)],\\n          foreground=[(\\&quot;selected\\&quot;, \\&quot;black\\&quot;)])\\ntree.tag_configure(\\&quot;pending\\&quot;, background=\\&quot;white\\&quot;)\\ntree.tag_configure(\\&quot;running\\&quot;, background=\\&quot;#FFFF66\\&quot;)  # \\u9ec4\\u8272\\ntree.tag_configure(\\&quot;success\\&quot;, background=\\&quot;#A0FFA0\\&quot;)  # \\u7eff\\u8272\\ntree.tag_configure(\\&quot;fail\\&quot;, background=\\&quot;#FFA0A0\\&quot;)     # \\u7c89\\u8272\\ntree.tag_configure(\\&quot;skipped\\&quot;, background=\\&quot;#D0D0D0\\&quot;)  # \\u7070\\u8272\\n\\n# ----------------\\u542f\\u52a8\\u65f6\\u52a0\\u8f7d\\u4e0a\\u6b21\\u4efb\\u52a1----------------\\nload_tasks_from_file()\\n\\nroot.mainloop()\\n&quot;,&quot;codeTypo&quot;:{&quot;desktop&quot;:10,&quot;tablet&quot;:15,&quot;mobile&quot;:14},&quot;width&quot;:{&quot;desktop&quot;:&quot;100%&quot;,&quot;tablet&quot;:&quot;101.7%&quot;,&quot;mobile&quot;:&quot;100%&quot;},&quot;height&quot;:{&quot;desktop&quot;:&quot;299px&quot;,&quot;tablet&quot;:&quot;0px&quot;,&quot;mobile&quot;:&quot;0px&quot;},&quot;align&quot;:&quot;&quot;,&quot;lineNumbers&quot;:true,&quot;theme&quot;:&quot;default&quot;,&quot;clipBoard&quot;:true,&quot;wordWrap&quot;:true,&quot;padding&quot;:{&quot;top&quot;:&quot;0px&quot;,&quot;right&quot;:&quot;0px&quot;,&quot;bottom&quot;:&quot;0px&quot;,&quot;left&quot;:&quot;0px&quot;},&quot;background&quot;:{&quot;color&quot;:&quot;#d3cfcf42&quot;},&quot;layout&quot;:{&quot;align&quot;:&quot;left&quot;},&quot;border&quot;:{&quot;color&quot;:&quot;#000&quot;,&quot;style&quot;:&quot;solid&quot;,&quot;width&quot;:&quot;0px&quot;},&quot;shadow&quot;:[],&quot;alignment&quot;:&quot;center&quot;,&quot;clipBoardColors&quot;:{&quot;color&quot;:&quot;#fff&quot;,&quot;bg&quot;:&quot;#00000024&quot;}}'><\/div>\r\n\r\n\t\t\n\n\n<h1 class=\"wp-block-heading\">\u5b89\u88c5\u4f9d\u8d56<\/h1>\n\n\n\n<ul class=\"wp-block-list\">\n<li>pip install PySimpleGUI<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">\u5269\u4f59\u65f6\u95f4\u7684\u63a8\u7b97<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">\u57fa\u672c\u516c\u5f0f<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5047\u8bbe\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5df2\u5b8c\u6210\u5de5\u4f5c\u91cf\uff1a<code>done<\/code>\uff08\u6bd4\u5982\u5df2\u7ecf\u62f7\u8d1d\u7684\u6587\u4ef6\u6570\u6216\u5b57\u8282\u6570\uff09<\/li>\n\n\n\n<li>\u603b\u5de5\u4f5c\u91cf\uff1a<code>total<\/code>\uff08\u6bd4\u5982\u603b\u6587\u4ef6\u6570\u6216\u603b\u5b57\u8282\u6570\uff09<\/li>\n\n\n\n<li>\u5df2\u7528\u65f6\u95f4\uff1a<code>elapsed<\/code>\uff08\u4ece\u5f00\u59cb\u5230\u73b0\u5728\u7684\u65f6\u95f4\uff09<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"476\" src=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/08\/image-27.png\" alt=\"\" class=\"wp-image-3747\"\/><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u73b0\u5b9e\u60c5\u51b5\u4f18\u5316<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u5b9e\u65f6\u66f4\u65b0<\/strong>\uff1a\u901f\u5ea6\u53ef\u80fd\u53d8\u5316\uff0c\u6240\u4ee5\u5269\u4f59\u65f6\u95f4\u901a\u5e38\u4f1a\u52a8\u6001\u66f4\u65b0\u3002<\/li>\n\n\n\n<li><strong>\u5e73\u6ed1\u5904\u7406<\/strong>\uff1a\u907f\u514d\u77ac\u65f6\u901f\u5ea6\u6ce2\u52a8\u5bfc\u81f4\u5269\u4f59\u65f6\u95f4\u5ffd\u9ad8\u5ffd\u4f4e\uff0c\u4e00\u822c\u53d6\u6700\u8fd1\u4e00\u6bb5\u65f6\u95f4\u7684\u5e73\u5747\u901f\u5ea6\u3002<\/li>\n\n\n\n<li><strong>\u5355\u4f4d\u8f6c\u6362<\/strong>\uff1a\u79d2 \u2192 \u5206\u949f \u2192 \u5c0f\u65f6\uff0c\u65b9\u4fbf\u7528\u6237\u67e5\u770b\u3002<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>\u754c\u9762 \u4ecb\u7ecd \u529f\u80fd\u7279\u70b9\uff1a \u9002\u7528\u573a\u666f\uff1a \u7f3a\u70b9\uff1a py\u4ee3\u7801 2.0 1.0 \u5b89\u88c5\u4f9d\u8d56 \u5269\u4f59\u65f6\u95f4\u7684\u63a8\u7b97 \u57fa\u672c\u516c\u5f0f \u5047\u8bbe [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3741","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/posts\/3741","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3741"}],"version-history":[{"count":4,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/posts\/3741\/revisions"}],"predecessor-version":[{"id":4285,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/posts\/3741\/revisions\/4285"}],"wp:attachment":[{"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3741"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}