基于Python打造高颜值软件卸载工具

 更新时间:2025年05月08日 09:45:59   作者:创客白泽  
在Windows系统中,自带的"添加/删除程序"功能一直饱受诟病,加载慢,功能弱,残留多,所以我们来使用Python打造一个高颜值软件的卸载工具吧

前言:为什么需要自制卸载工具

在Windows系统中,自带的"添加/删除程序"功能一直饱受诟病:加载慢、功能弱、残留多。第三方卸载工具如GeekUninstaller虽然好用,但毕竟是闭源商业软件。今天我们将用Python+tkinter打造一款颜值与实力并存的卸载工具,具备以下杀手级特性:

  • 现代化UI界面(暗黑主题+高亮配色)
  • 精准程序扫描(三路注册表探测)
  • 强力卸载模式(支持MSI静默卸载)
  • 智能残留清理(全盘扫描关联文件)
  • 原生图标提取(EXE文件图标解析)

一、核心功能架构设计

1.1 技术栈选型

技术组件作用说明替代方案
tkinterGUI界面开发PyQt/PySide
winregWindows注册表访问_winreg
Pillow图标图像处理OpenCV
pywin32Windows API调用ctypes
shutil文件系统操作os模块

1.2 程序流程图

二、关键技术实现详解

2.1 多源注册表扫描(核心代码解析)

def load_installed_programs(self):
    reg_paths = [
        (winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"),
        # 64位系统兼容路径
        (winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\WOW6432Node\..."), 
        # 当前用户安装路径
        (winreg.HKEY_CURRENT_USER, r"SOFTWARE\Microsoft\...")
    ]
    
    for hive, path in reg_paths:
        try:
            with winreg.OpenKey(hive, path) as key:
                for i in range(winreg.QueryInfoKey(key)[0]):
                    # 提取程序信息...
                    program = {
                        "name": name,
                        "version": version,
                        "install_location": install_path,
                        "uninstall_string": uninstall_cmd
                    }

技术要点:

  • 同时扫描HKLM和HKCU两大主键
  • 处理64位系统的WOW6432Node兼容路径
  • 异常处理确保扫描过程不中断

2.2 动态图标提取技术

def get_icon_from_exe(self, exe_path):
    # 使用Win32 API提取图标
    large, small = win32gui.ExtractIconEx(exe_path, 0)
    hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
    
    # 创建兼容位图
    hbmp = win32ui.CreateBitmap()
    hbmp.CreateCompatibleBitmap(hdc, 16, 16)
    
    # 转换为PIL图像
    bmpstr = hbmp.GetBitmapBits(True)
    icon = Image.frombuffer('RGB', (16,16), bmpstr, 'raw', 'BGRX', 0, 1)
    return ImageTk.PhotoImage(icon)

创新点:

  • 直接从EXE/DLL提取原始图标
  • 自动降采样到16x16尺寸
  • 异常时回退到默认图标

三、高级功能实现

3.1 智能文件大小计算

def get_program_size(self, path):
    total = 0
    for root, dirs, files in os.walk(path):
        for f in files:
            try:
                total += os.path.getsize(os.path.join(root, f))
            except:
                continue
    return total

​​​​​​​def format_size(self, size):
    # 智能转换单位
    units = ['B', 'KB', 'MB', 'GB']
    for unit in units:
        if size < 1024.0:
            return f"{size:.1f} {unit}"
        size /= 1024.0
    return f"{size:.1f} TB"

3.2 强力卸载模式

卸载类型处理方式示例命令
标准卸载程序直接执行UninstallStringC:\Program Files\...
MSI安装包调用msiexec静默卸载msiexec /x {GUID}
无卸载程序提示手动删除-

四、UI美化实战技巧

4.1 现代化暗黑主题

self.bg_color = "#2d2d2d"  # 背景色
self.fg_color = "#ffffff"   # 前景色
self.accent_color = "#4CAF50" # 强调色

style = ttk.Style()
style.theme_use("clam")
style.configure("Treeview", 
    background="#3d3d3d",
    foreground=self.fg_color,
    fieldbackground="#3d3d3d"
)

4.2 响应式布局设计

# 主界面采用Pack布局
main_frame.pack(fill=tk.BOTH, expand=True)

# 左侧列表区域
list_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

# 右侧按钮区域
button_frame.pack(side=tk.RIGHT, fill=tk.Y)

五、性能优化方案

5.1 图标缓存机制

self.icon_cache = {}  # 缓存字典

def get_program_icon(self, program):
    if program['name'] in self.icon_cache:
        return self.icon_cache[program['name']]
    
    icon = self._extract_icon(program)
    self.icon_cache[program['name']] = icon
    return icon

5.2 多线程加载

from threading import Thread

def load_data_async(self):
    Thread(target=self.load_installed_programs, daemon=True).start()

项目总结与展望

通过本项目,我们实现了:

  • 完整的程序卸载管理功能
  • 媲美商业软件的UI体验
  • 高效的注册表扫描机制
  • 智能化的残留检测

未来优化方向:

  • 增加云端垃圾文件特征库
  • 实现卸载历史记录功能
  • 添加软件更新检测模块

完整项目源码

import os
import winreg
import subprocess
import shutil
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
from PIL import Image, ImageTk
import ctypes

class GeekUninstallerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("PyGeek Uninstaller")
        self.root.geometry("900x600")
        self.root.minsize(800, 500)
        
        # 设置主题颜色
        self.bg_color = "#2d2d2d"
        self.fg_color = "#ffffff"
        self.accent_color = "#4CAF50"
        self.secondary_color = "#2196F3"
        self.warning_color = "#FF5722"
        self.highlight_color = "#FFC107"
        
        # 初始化样式
        self.setup_styles()
        
        # 创建UI
        self.create_widgets()
        
        # 加载已安装程序
        self.load_installed_programs()
    
    def setup_styles(self):
        style = ttk.Style()
        style.theme_use("clam")
        
        # 树状视图样式
        style.configure("Treeview", 
            background="#3d3d3d", 
            foreground=self.fg_color, 
            fieldbackground="#3d3d3d", 
            borderwidth=0
        )
        style.configure("Treeview.Heading", 
            background="#4d4d4d", 
            foreground=self.fg_color, 
            relief=tk.FLAT
        )
        style.map("Treeview", background=[("selected", self.secondary_color)])
        
        # 配置主窗口背景
        self.root.configure(bg=self.bg_color)
    
    def create_widgets(self):
        # 顶部标题栏
        header_frame = tk.Frame(self.root, bg=self.bg_color)
        header_frame.pack(fill=tk.X, padx=10, pady=10)
        
        # 标题
        title_label = tk.Label(
            header_frame, 
            text="PyGeek Uninstaller", 
            font=("Segoe UI", 18, "bold"), 
            fg=self.highlight_color, 
            bg=self.bg_color
        )
        title_label.pack(side=tk.LEFT)
        
        # 搜索框
        search_frame = tk.Frame(header_frame, bg=self.bg_color)
        search_frame.pack(side=tk.RIGHT, fill=tk.X, expand=True)
        
        search_label = tk.Label(
            search_frame, 
            text="Search:", 
            font=("Segoe UI", 10), 
            fg=self.fg_color, 
            bg=self.bg_color
        )
        search_label.pack(side=tk.LEFT, padx=(20, 5))
        
        self.search_var = tk.StringVar()
        self.search_var.trace("w", self.filter_programs)
        search_entry = tk.Entry(
            search_frame, 
            textvariable=self.search_var, 
            font=("Segoe UI", 10), 
            bg="#3d3d3d", 
            fg=self.fg_color, 
            insertbackground=self.fg_color, 
            relief=tk.FLAT
        )
        search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, ipady=2)
        
        # 主内容区域
        main_frame = tk.Frame(self.root, bg=self.bg_color)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
        
        # 程序列表
        list_frame = tk.Frame(main_frame, bg=self.bg_color)
        list_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 树状视图
        self.tree = ttk.Treeview(
            list_frame, 
            columns=("name", "publisher", "version", "size"), 
            selectmode="extended"
        )
        
        # 配置列
        self.tree.heading("#0", text="Icon", anchor=tk.W)
        self.tree.heading("name", text="Name", anchor=tk.W, command=lambda: self.treeview_sort_column(self.tree, "name", False))
        self.tree.heading("publisher", text="Publisher", anchor=tk.W, command=lambda: self.treeview_sort_column(self.tree, "publisher", False))
        self.tree.heading("version", text="Version", anchor=tk.W, command=lambda: self.treeview_sort_column(self.tree, "version", False))
        self.tree.heading("size", text="Size", anchor=tk.W, command=lambda: self.treeview_sort_column(self.tree, "size", False))
        
        self.tree.column("#0", width=30, minwidth=30, stretch=tk.NO)
        self.tree.column("name", width=250, minwidth=150, stretch=tk.YES)
        self.tree.column("publisher", width=200, minwidth=100, stretch=tk.YES)
        self.tree.column("version", width=100, minwidth=70, stretch=tk.NO)
        self.tree.column("size", width=100, minwidth=70, stretch=tk.NO)
        
        # 滚动条
        scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.tree.pack(fill=tk.BOTH, expand=True)
        
        # 绑定双击事件
        self.tree.bind("<Double-1>", self.show_program_details)
        
        # 操作按钮区域
        button_frame = tk.Frame(main_frame, bg=self.bg_color)
        button_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=(0, 10))
        
        # 按钮样式
        button_style = {
            "font": ("Segoe UI", 10), 
            "bg": "#4d4d4d", 
            "fg": self.fg_color, 
            "activebackground": self.secondary_color, 
            "activeforeground": self.fg_color, 
            "relief": tk.FLAT, 
            "bd": 0, 
            "padx": 15, 
            "pady": 8
        }
        
        # 操作按钮
        self.uninstall_btn = tk.Button(
            button_frame, 
            text="Uninstall", 
            command=self.uninstall_selected, 
            **button_style
        )
        self.uninstall_btn.pack(fill=tk.X, pady=(0, 5))
        
        self.force_btn = tk.Button(
            button_frame, 
            text="Force Remove", 
            command=self.force_remove, 
            **button_style
        )
        self.force_btn.pack(fill=tk.X, pady=(0, 5))
        
        self.details_btn = tk.Button(
            button_frame, 
            text="Details", 
            command=self.show_program_details, 
            **button_style
        )
        self.details_btn.pack(fill=tk.X, pady=(0, 5))
        
        self.clean_btn = tk.Button(
            button_frame, 
            text="Clean Residues", 
            command=self.clean_residues, 
            **button_style
        )
        self.clean_btn.pack(fill=tk.X, pady=(0, 5))
        
        self.refresh_btn = tk.Button(
            button_frame, 
            text="Refresh", 
            command=self.refresh_list, 
            **button_style
        )
        self.refresh_btn.pack(fill=tk.X, pady=(0, 5))
        
        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("Ready")
        status_bar = tk.Label(
            self.root, 
            textvariable=self.status_var, 
            font=("Segoe UI", 9), 
            fg=self.fg_color, 
            bg="#3d3d3d", 
            anchor=tk.W, 
            relief=tk.SUNKEN
        )
        status_bar.pack(fill=tk.X, side=tk.BOTTOM, ipady=5)
    
    def treeview_sort_column(self, tv, col, reverse):
        l = [(tv.set(k, col), k) for k in tv.get_children('')]
        
        # 尝试转换为数字进行排序
        try:
            l.sort(key=lambda t: float(t[0]) if t[0].replace('.', '').isdigit() else t[0], reverse=reverse)
        except:
            l.sort(reverse=reverse)
        
        # 重新排列项目
        for index, (val, k) in enumerate(l):
            tv.move(k, '', index)
        
        # 下次反向排序
        tv.heading(col, command=lambda: self.treeview_sort_column(tv, col, not reverse))
    
    def load_installed_programs(self):
        self.tree.delete(*self.tree.get_children())
        self.programs = []
        
        # 从注册表获取已安装程序
        reg_paths = [
            (winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"),
            (winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"),
            (winreg.HKEY_CURRENT_USER, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")
        ]
        
        for hive, path in reg_paths:
            try:
                with winreg.OpenKey(hive, path) as key:
                    for i in range(0, winreg.QueryInfoKey(key)[0]):
                        try:
                            subkey_name = winreg.EnumKey(key, i)
                            with winreg.OpenKey(key, subkey_name) as subkey:
                                try:
                                    name = winreg.QueryValueEx(subkey, "DisplayName")[0]
                                    if not name:
                                        continue
                                    
                                    publisher = winreg.QueryValueEx(subkey, "Publisher")[0] if winreg.QueryValueEx(subkey, "Publisher") else ""
                                    version = winreg.QueryValueEx(subkey, "DisplayVersion")[0] if winreg.QueryValueEx(subkey, "DisplayVersion") else ""
                                    install_location = winreg.QueryValueEx(subkey, "InstallLocation")[0] if winreg.QueryValueEx(subkey, "InstallLocation") else ""
                                    uninstall_string = winreg.QueryValueEx(subkey, "UninstallString")[0] if winreg.QueryValueEx(subkey, "UninstallString") else ""
                                    size = self.get_program_size(install_location)
                                    
                                    program = {
                                        "name": name,
                                        "publisher": publisher,
                                        "version": version,
                                        "size": size,
                                        "install_location": install_location,
                                        "uninstall_string": uninstall_string,
                                        "reg_key": f"{path}\\{subkey_name}",
                                        "hive": hive
                                    }
                                    
                                    self.programs.append(program)
                                    
                                    # 插入到树状视图
                                    self.tree.insert("", "end", values=(
                                        name, 
                                        publisher, 
                                        version, 
                                        self.format_size(size)
                                    ))
                                except (WindowsError, ValueError):
                                    continue
                        except (WindowsError, ValueError):
                            continue
            except WindowsError:
                continue
        
        # 按名称排序
        self.programs.sort(key=lambda x: x["name"].lower())
        self.treeview_sort_column(self.tree, "name", False)
        
        self.status_var.set(f"Loaded {len(self.programs)} programs")
    
    def get_program_size(self, install_location):
        if not install_location or not os.path.isdir(install_location):
            return 0
        
        total_size = 0
        for dirpath, dirnames, filenames in os.walk(install_location):
            for f in filenames:
                fp = os.path.join(dirpath, f)
                try:
                    total_size += os.path.getsize(fp)
                except:
                    continue
        return total_size
    
    def format_size(self, size):
        if size == 0:
            return "N/A"
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024.0:
                return f"{size:.1f} {unit}"
            size /= 1024.0
        return f"{size:.1f} TB"
    
    def filter_programs(self, *args):
        query = self.search_var.get().lower()
        for item in self.tree.get_children():
            values = self.tree.item(item)["values"]
            if query in values[0].lower() or query in values[1].lower():
                self.tree.selection_set(item)
                self.tree.see(item)
            else:
                self.tree.selection_remove(item)
    
    def get_selected_program(self):
        selected_items = self.tree.selection()
        if not selected_items:
            messagebox.showwarning("Warning", "Please select a program first!")
            return None
        
        item = selected_items[0]
        values = self.tree.item(item)["values"]
        
        for program in self.programs:
            if program["name"] == values[0] and program["publisher"] == values[1]:
                return program
        
        return None
    
    def show_program_details(self, event=None):
        program = self.get_selected_program()
        if not program:
            return
        
        details_window = tk.Toplevel(self.root)
        details_window.title(f"Details - {program['name']}")
        details_window.geometry("600x400")
        details_window.configure(bg=self.bg_color)
        
        # 详细信息文本
        details_text = scrolledtext.ScrolledText(
            details_window, 
            wrap=tk.WORD, 
            font=("Consolas", 10), 
            bg="#3d3d3d", 
            fg=self.fg_color, 
            insertbackground=self.fg_color
        )
        details_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 添加信息
        details = f"""Program Name: {program['name']}
Publisher: {program['publisher']}
Version: {program['version']}
Size: {self.format_size(program['size'])}
Install Location: {program['install_location']}
Uninstall Command: {program['uninstall_string']}
Registry Key: {program['reg_key']}
"""
        details_text.insert(tk.END, details)
        details_text.configure(state="disabled")
        
        # 关闭按钮
        close_btn = tk.Button(
            details_window, 
            text="Close", 
            command=details_window.destroy, 
            font=("Segoe UI", 10), 
            bg="#4d4d4d", 
            fg=self.fg_color, 
            activebackground=self.secondary_color, 
            activeforeground=self.fg_color, 
            relief=tk.FLAT
        )
        close_btn.pack(pady=(0, 10))
    
    def uninstall_selected(self):
        program = self.get_selected_program()
        if not program:
            return
        
        if not program["uninstall_string"]:
            messagebox.showerror("Error", "No uninstall command found for this program!")
            return
        
        try:
            # 运行卸载命令
            if program["uninstall_string"].lower().endswith(".msi"):
                # MSI 包
                cmd = f'msiexec /x "{program["uninstall_string"]}" /quiet'
            else:
                # 普通卸载程序
                cmd = program["uninstall_string"]
            
            subprocess.Popen(cmd, shell=True)
            self.status_var.set(f"Uninstalling {program['name']}...")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to start uninstaller: {str(e)}")
    
    def force_remove(self):
        program = self.get_selected_program()
        if not program:
            return
        
        if not messagebox.askyesno("Warning", 
                f"Force removal will delete all files and registry entries for {program['name']}.\n"
                "This action cannot be undone. Continue?"):
            return
        
        # 删除安装目录
        if program["install_location"] and os.path.isdir(program["install_location"]):
            try:
                shutil.rmtree(program["install_location"])
                self.status_var.set(f"Deleted installation folder: {program['install_location']}")
            except Exception as e:
                messagebox.showerror("Error", f"Failed to delete installation folder: {str(e)}")
        
        # 删除注册表项
        try:
            hive, path = program["hive"], program["reg_key"]
            with winreg.OpenKey(hive, path.replace("\\", "/"), 0, winreg.KEY_ALL_ACCESS) as key:
                winreg.DeleteKey(hive, path)
            self.status_var.set(f"Deleted registry key: {path}")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to delete registry key: {str(e)}")
        
        # 刷新列表
        self.refresh_list()
        messagebox.showinfo("Success", f"{program['name']} has been force removed!")
    
    def clean_residues(self):
        program = self.get_selected_program()
        if not program:
            return
        
        # 查找残留文件
        residues = []
        if program["install_location"] and os.path.isdir(program["install_location"]):
            residues.append(program["install_location"])
        
        # 检查常见残留位置
        common_locations = [
            os.path.join(os.environ["APPDATA"], program["name"]),
            os.path.join(os.environ["LOCALAPPDATA"], program["name"]),
            os.path.join(os.environ["PROGRAMDATA"], program["name"]),
            os.path.join(os.environ["USERPROFILE"], "AppData", "Local", program["name"]),
            os.path.join(os.environ["USERPROFILE"], "AppData", "Roaming", program["name"])
        ]
        
        for loc in common_locations:
            if os.path.exists(loc):
                residues.append(loc)
        
        if not residues:
            messagebox.showinfo("Info", "No residual files found for this program.")
            return
        
        # 显示确认对话框
        residue_text = "\n".join(residues)
        if not messagebox.askyesno("Confirm", 
                f"The following residual files/folders will be deleted:\n\n{residue_text}\n\nContinue?"):
            return
        
        # 删除残留文件
        success = True
        for residue in residues:
            try:
                if os.path.isdir(residue):
                    shutil.rmtree(residue)
                else:
                    os.remove(residue)
                self.status_var.set(f"Deleted residue: {residue}")
            except Exception as e:
                messagebox.showerror("Error", f"Failed to delete {residue}: {str(e)}")
                success = False
        
        if success:
            messagebox.showinfo("Success", "Residual files have been cleaned successfully!")
    
    def refresh_list(self):
        self.status_var.set("Refreshing program list...")
        self.root.update()
        self.load_installed_programs()
        self.status_var.set("Program list refreshed")

def main():
    # 启用DPI感知
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(1)
    except:
        pass
    
    root = tk.Tk()
    app = GeekUninstallerApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()

互动讨论

Q:为什么选择tkinter而不是PyQt?

A:tkinter作为Python标准库,具有更好的兼容性和更小的体积,适合分发小型工具。

Q:如何增强卸载能力?

​​​​​​​A:可以集成PowerShell的Remove-MSIXPackage等现代卸载方案。

以上就是基于Python打造高颜值软件卸载工具的详细内容,更多关于Python软件卸载的资料请关注脚本之家其它相关文章!

相关文章

  • PyCharm vs VSCode,作为python开发者,你更倾向哪种IDE呢?

    PyCharm vs VSCode,作为python开发者,你更倾向哪种IDE呢?

    这篇文章主要介绍了PyCharm和vscode作为python ide的优劣,帮助你选择适合自己的ide,感兴趣的朋友可以了解下
    2020-08-08
  • YOLOv5车牌识别实战教程(七)实时监控与分析

    YOLOv5车牌识别实战教程(七)实时监控与分析

    这篇文章主要介绍了YOLOv5车牌识别实战教程(七)实时监控与分析,在这个教程中,我们将一步步教你如何使用YOLOv5进行车牌识别,帮助你快速掌握YOLOv5车牌识别技能,需要的朋友可以参考下
    2023-04-04
  • nlp计数法应用于PTB数据集示例详解

    nlp计数法应用于PTB数据集示例详解

    这篇文章主要为大家介绍了nlp计数法应用于PTB数据集示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • 如何使用Python读取xml文件

    如何使用Python读取xml文件

    这篇文章主要介绍了如何使用Python读取xml文件,关于python读取xml文章很多,但大多文章都是贴一个xml文件,然后再贴个处理文件的代码希望这篇文章可以更通俗易懂的教如何使用python 来读取xml 文件
    2023-04-04
  • Java文件与类动手动脑实例详解

    Java文件与类动手动脑实例详解

    在本篇文章里小编给大家整理的是关于Java文件与类动手动脑实例知识点,有需要的朋友们学习参考下。
    2019-11-11
  • numpy系列之数组合并(横向和纵向)

    numpy系列之数组合并(横向和纵向)

    本文主要介绍了numpy系列之数组合并(横向和纵向),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Python脚本读取Consul配置信息的方法示例

    Python脚本读取Consul配置信息的方法示例

    本文主要介绍了Python脚本读取Consul配置信息的方法示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • windows安装python超详细图文教程

    windows安装python超详细图文教程

    今天带各位小伙伴学习怎么在windows上安装python,文中有非常详细的图文介绍,对初步学习python的小伙伴们有很好地帮助,需要的朋友可以参考下
    2021-05-05
  • python中MethodType方法介绍与使用示例

    python中MethodType方法介绍与使用示例

    这篇文章主要给大家介绍了关于python中MethodType方法的相关资料,文中通过示例代码给大家介绍的非常详细,并给出了详细的注释供大家理解学习,需要的朋友可以参考借鉴,下面跟着小编来一起学习学习吧。
    2017-08-08
  • python在一个范围内取随机数的简单实例

    python在一个范围内取随机数的简单实例

    在本篇内容里小编给大家分享了关于python在一个范围内取随机数的简单实例内容,有需要的朋友们可以学习下。
    2020-08-08

最新评论