• [专题汇总] 二月技术干货合集【合集贴】
    1.Docker应用部署(Mysql、tomcat、Redis、redis)https://bbs.huaweicloud.com/forum/thread-0251176000289103057-1-1.html    2. 鸿蒙NEXT开发案例:随机数生成https://bbs.huaweicloud.com/forum/thread-0226175856046738051-1-1.html3.ExaGear for Server on Ubuntuhttps://bbs.huaweicloud.com/forum/thread-02127175583262901024-1-1.html4.惊叹数据结构之美,品味排序算法之妙:对快排的详细介绍 -转载https://bbs.huaweicloud.com/forum/thread-0210175572143077031-1-1.html5.修改 Docker 容器的 http_proxy 和 https_proxy -转载https://bbs.huaweicloud.com/forum/thread-02127175572007355023-1-1.html6.【Linux】gdb_进程概念-转载https://bbs.huaweicloud.com/forum/thread-0257175571963347026-1-1.html7.详解Redis之事务-转载https://bbs.huaweicloud.com/forum/thread-0251175571892832022-1-1.html8.Python中的对象关系映射SQLAlchemy ORM在Web开发中的实践 -转载https://bbs.huaweicloud.com/forum/thread-0218175571849778026-1-1.html9.鸿蒙NEXT开发案例:颜文字搜索器https://bbs.huaweicloud.com/forum/thread-0225175848016900053-1-1.html10.鸿蒙NEXT开发案例:经纬度距离计算https://bbs.huaweicloud.com/forum/thread-02127175847897096052-1-1.html11.鸿蒙NEXT开发案例:世界时间表https://bbs.huaweicloud.com/forum/thread-0220175848120824046-1-1.html12.鸿蒙NEXT开发案例:保质期计算https://bbs.huaweicloud.com/forum/thread-0257175848211239048-1-1.html13.鸿蒙NEXT开发案例:九宫格随机https://bbs.huaweicloud.com/forum/thread-0257175848540835049-1-1.html14.Python中的对象关系映射SQLAlchemy ORM在Web开发中的实践 -转载https://bbs.huaweicloud.com/forum/thread-0218175571849778026-1-1.html15.【MySQL】 表的操作-转载https://bbs.huaweicloud.com/forum/thread-0220174982575490008-1-1.html
  • [专题汇总] 2025年技术干货合集第二弹【2月份干货】
    25年的第二次合集来了,涵盖多方面内容,供大家阅读。1.解读为什么@Autowired在属性上被警告,在setter方法上不被警告问题https://bbs.huaweicloud.com/forum/thread-0226176114797408069-1-1.html2.C 与 C++ 中的 const 常量与数组大小的关系对比分析【转】https://bbs.huaweicloud.com/forum/thread-0225176114407160080-1-1.html3. Java对象和JSON字符串之间的转换方法(全网最清晰)【转】https://bbs.huaweicloud.com/forum/thread-0218176114284451074-1-1.html4.Python中利用json库进行JSON数据处理详解【转】https://bbs.huaweicloud.com/forum/thread-0225176114218197079-1-1.html5.Python使用sys.path查看当前的模块搜索路径【转】https://bbs.huaweicloud.com/forum/thread-0225176047116377070-1-1.html6.PyTorch环境中CUDA版本冲突问题排查与解决方案【转】https://bbs.huaweicloud.com/forum/thread-0225176047065418069-1-1.html7.python 3.8 的anaconda下载方法【转】https://bbs.huaweicloud.com/forum/thread-02127176045871929063-1-1.html8.Python实现批量Excel拆分功能【转】https://bbs.huaweicloud.com/forum/thread-0218176045720424067-1-1.html9.Python中常用的四种取整方式分享【转】https://bbs.huaweicloud.com/forum/thread-0218176037491495065-1-1.html10.Python自动化处理手机验证码【转】https://bbs.huaweicloud.com/forum/thread-0210176037394123079-1-1.html11. Docker应用部署(Mysql、tomcat、Redis、redis)https://bbs.huaweicloud.com/forum/thread-0251176000289103057-1-1.html12.使用Python实现文件重命名的三种方法【转】https://bbs.huaweicloud.com/forum/thread-0210175967963879073-1-1.html13.python安装whl包并解决依赖关系的实现【转】https://bbs.huaweicloud.com/forum/thread-0226175967884244062-1-1.html14.Python轻松实现批量邮件自动化详解【转】https://bbs.huaweicloud.com/forum/thread-0251175967723301055-1-1.html15.Python脚本实现图片文件批量命名【转】https://bbs.huaweicloud.com/forum/thread-0226175967493359061-1-1.html16.Python中多线程和多进程的基本用法详解【转】https://bbs.huaweicloud.com/forum/thread-0251175967381425054-1-1.html17.鸿蒙NEXT开发案例:随机数生成https://bbs.huaweicloud.com/forum/thread-0226175856046738051-1-1.html18.鸿蒙NEXT开发案例:简体繁体转换器https://bbs.huaweicloud.com/forum/thread-0251175855906014051-1-1.html19.鸿蒙NEXT开发案例:血型遗传计算https://bbs.huaweicloud.com/forum/thread-0220175855724260049-1-1.html20.鸿蒙NEXT开发案例:数字转中文大小写https://bbs.huaweicloud.com/forum/thread-0225175850374977055-1-1.html 
  • [技术干货] Python中利用json库进行JSON数据处理详解【转】
    Python的json库用于处理JSON(JavaScript Object Notation)数据格式。JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。Python的json库提供了函数来编码(将Python对象转换为JSON字符串)和解码(将JSON 字符串转换为Python对象)JSON数据。编码Python对象为JSON字符串使用json.dumps()方法将Python对象编码为JSON字符串:12345678910111213141516import json data = {    "name": "Morris",    "age": 18,    "mail": "Morris@18.com"} # dict -> jsonstr = json.dumps(data, indent=4)print(str) arr = [data, data]# list -> jsonarr_str = json.dumps(arr, indent=4)print(arr_str)运行结果如下:{    "name": "Morris",    "age": 18,    "mail": "Morris@18.com"}[    {        "name": "Morris",        "age": 18,        "mail": "Morris@18.com"    },    {        "name": "Morris",        "age": 18,        "mail": "Morris@18.com"    }]indent参数用于美化输出,使JSON字符串更具可读性。解码JSON字符串为Python对象使用json.loads()方法将JSON字符串解码为Python对象(通常是字典或列表):1234567891011121314151617181920212223242526272829import json object_str = """{    "name": "Morris",    "age": 18,    "mail": "Morris@18.com"}""" obj = json.loads(object_str)print(obj) array_str = """[    {        "name": "Morris",        "age": 18,        "mail": "Morris@18.com"    },    {        "name": "Morris",        "age": 18,        "mail": "Morris@18.com"    }]"""arr = json.loads(array_str)print(arr)运行结果如下:{'name': 'Morris', 'age': 18, 'mail': 'Morris@18.com'}[{'name': 'Morris', 'age': 18, 'mail': 'Morris@18.com'}, {'name': 'Morris', 'age': 18, 'mail': 'Morris@18.com'}]将Python对象写入JSON文件json.dump()函数也是用于将Python对象编码成JSON格式,但它直接将编码后的数据写入到一个文件中,而不是返回字符串。1234567891011import json data = {    "name": "Morris",    "age": 18,    "mail": "Morris@18.com"} ​​​​​​​# dict -> json filewith open('data.json', 'w', encoding='utf-8') as f:    json.dump(data, f, ensure_ascii=False, indent=4) 从文件中读取JSON数据使用json.load()方法从文件中读取JSON数据并将其解析为Python对象:123456import json # json file -> dictwith open('data.json', 'r', encoding='utf-8') as f:    obj = json.load(f)    print(obj)运行结果如下:{'name': 'Morris', 'age': 18, 'mail': 'Morris@18.com'}处理复杂对象有时你可能需要处理包含复杂对象(如自定义类实例)的JSON数据。你可以通过实现自定义的编码器和解码器来处理这些对象。自定义编码器要实现自定义编码器,你需要创建一个继承自json.JSONEncoder的类,并重写default方法:123456789101112131415161718import jsonfrom datetime import datetime class CustomEncoder(json.JSONEncoder):    def default(self, obj):        if isinstance(obj, datetime):            return obj.strftime("%Y-%m-%d %H:%M:%S")        # 其他自定义处理        return json.JSONEncoder.default(self, obj)  data = {    "name": "Morris",    "timestamp": datetime.now()} json_str = CustomEncoder().encode(data)print(json_str)运行结果如下:{"name": "Morris", "timestamp": "2024-12-31 14:16:55"}自定义解码器要实现自定义解码器,你需要创建一个继承自json.JSONDecoder的类,并重写object_hook或object_pairs_hook方法:1234567891011121314151617181920212223242526import jsonfrom datetime import datetime  def datetime_parser(dct):    for key, value in dct.items():        if isinstance(value, str):            try:                # 假设日期格式是 "YYYY-MM-DD"                dct[key] = datetime.strptime(value, "%Y-%m-%d %H:%M:%S")            except ValueError:                # 如果不是日期格式,则保持原样                pass    return dct  json_str = """{    "name": "Morris",    "timestamp": "2024-12-31 14:16:55"}""" data = json.loads(json_str, object_hook=datetime_parser)print(data)print(data['timestamp']) 运行结果如下:{'name': 'Morris', 'timestamp': datetime.datetime(2024, 12, 31, 14, 16, 55)}2024-12-31 14:16:55
  • [技术干货] Python使用sys.path查看当前的模块搜索路径【转】
    功能讲解以下是关于 sys.path 的详细解释:用途:sys.path 决定了 Python 解释器在导入模块时的搜索顺序。它可以帮助你组织代码,确保模块可以被正确导入。组成:sys.path 通常由以下几部分组成:当前脚本所在的目录。PYTHONPATH(环境变量)设置的目录。安装 Python 时默认的库路径(例如:lib/pythonX.X/site-packages)。查看 sys.path:你可以在 Python 解释器中通过以下代码查看 sys.path 的内容:12import sysprint(sys.path)修改 sys.path:你可以修改 sys.path 来添加或删除搜索路径,例如:12import syssys.path.append('/path/to/your/module')注意:修改 sys.path 应该谨慎操作,因为这可能会影响到模块的导入。注意事项:当你在导入模块时遇到“ModuleNotFoundError”,很可能是因为模块所在的路径不在 sys.path 中。在某些情况下,为了防止路径问题,建议使用绝对导入而不是相对导入。示例:假设你有以下文件结构:1234project/├── main.py└── my_module/    └── my_module.py在 main.py 中,你想导入 my_module.py。如果 project/ 不在 sys.path 中,你会遇到导入错误。在这种情况下,你可以修改 main.py:123import syssys.path.append('/path/to/project')import my_module.my_module总之,理解 sys.path 对于模块导入和 Python 项目组织非常重要。正确配置 sys.path 可以帮助你更有效地管理代码和依赖。操作示例下面是如何查看和操作sys.path的步骤:查看sys.path首先,你需要导入Python的sys模块,因为sys.path是sys模块的一部分。然后,你可以通过打印sys.path来查看当前的模块搜索路径。下面是一个简单的例子:123import sys# 打印当前的模块搜索路径print(sys.path)运行这段代码后,你会看到输出当前的sys.path列表,其中包含了Python解释器查找模块的目录。修改sys.path如果你想要添加或修改模块的搜索路径,可以直接修改sys.path列表。例如,添加一个新的目录到搜索路径:1234567import sys# 添加一个新的目录到搜索路径new_directory = '/path/to/your/module'if new_directory not in sys.path:    sys.path.append(new_directory)# 再次打印查看修改后的路径print(sys.path)注意事项修改sys.path会影响到当前Python进程中的所有模块查找操作,因此需要谨慎进行。添加的目录必须是有效的Python模块目录(即包含有__init__.py文件的目录,或者在Python 3.3及以上版本中,可以是包含有__init__.pyi文件的目录)。在使用第三方库或模块时,确保它们的安装位置被包含在sys.path中,否则Python解释器将无法找到并导入这些模块。通过上述方法,你可以方便地查看和修改Python的模块搜索路径。
  • [技术干货] PyTorch环境中CUDA版本冲突问题排查与解决方案【转】
    引言在使用 PyTorch 进行深度学习开发时,CUDA 版本兼容性问题是个老生常谈的话题。本文将通过一次真实的排查过程,剖析 PyTorch 虚拟环境自带 CUDA 运行时库与系统全局 CUDA 环境冲突的场景,并一步步分析问题、定位原因,并最终给出解决方案。问题复现:ImportError: undefined symbol始于一个看似简单的 import torch 语句(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ pythonPython 3.12.9 (main, Feb 12 2025, 14:50:50) [Clang 19.1.6 ] on linuxType "help", "copyright", "credits" or "license" for more information.>>> import torch>>> Traceback (most recent call last):>>> File "<stdin>", line 1, in <module>>>> File "/home/wangh/codes/ModelForger/.venv/lib/python3.12/site-packages/torch/__init__.py", line 367, in <module>>>> from torch._C import *  # noqa: F403>>> ^^^^^^^^^^^^^^^^^^^^^^>>> ImportError: /home/wangh/codes/ModelForger/.venv/lib/python3.12/site-packages/torch/lib/../../nvidia/cusparse/lib/libcusparse.so.12: undefined symbol: __nvJitLinkComplete_12_4, version libnvJitLink.so.12错误信息很明确,在 libcusparse.so.12 中找不到符号 __nvJitLinkComplete_12_4,这通常意味着存在版本不匹配的问题。 初步排查:环境 & CUDA 版本首先,我们检查一下环境和 CUDA 版本(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ echo $LD_LIBRARY_PATH/usr/local/cuda/lib64:(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ nvcc --versionnvcc: NVIDIA (R) Cuda compiler driverCopyright (c) 2005-2023 NVIDIA CorporationBuilt on Wed_Nov_22_10:17:15_PST_2023Cuda compilation tools, release 12.3, V12.3.107Build cuda_12.3.r12.3/compiler.33567101_0(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ uv pip list | grep nvidiaUsing Python 3.12.9 environment at: /home/wangh/codes/ModelForger/.venvnvidia-cublas-cu12        12.4.5.8nvidia-cuda-cupti-cu12    12.4.127nvidia-cuda-nvrtc-cu12    12.4.127nvidia-cuda-runtime-cu12  12.4.127nvidia-cudnn-cu12         9.1.0.70nvidia-cufft-cu12         11.2.1.3nvidia-curand-cu12        10.3.5.147nvidia-cusolver-cu12      11.6.1.9nvidia-cusparse-cu12      12.3.1.170nvidia-nccl-cu12          2.21.5nvidia-nvjitlink-cu12     12.4.127nvidia-nvtx-cu12          12.4.127发现了两个关键信息nvcc --version 系统安装的 CUDA 版本是 12.3。nvidia-* 虚拟环境安装的 nvjitlink 版本号为 12.4.127。根据错误信息可知,PyTorch 虚拟环境中的动态库 libcusparse.so.12 需要的正是 libnvJitLink.so.12 的 __nvJitLinkComplete_12_4 版本,pip 安装的依赖包版本自身没有问题,因此推测可能错误链接到了系统中 CUDA 12.3 的 libnvJitLink.so.12。 分析:动态链接库加载路径为了验证猜想,我们使用 patchelf 和 ldd 命令查看 libcusparse.so.12 的动态链接状态:(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ patchelf --print-rpath libcusparse.so.12$ORIGIN:$ORIGIN/../../nvjitlink/lib(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ ldd libcusparse.so.12        linux-vdso.so.1 (0x00007ffc507e2000)        libnvJitLink.so.12 => /usr/local/cuda/lib64/libnvJitLink.so.12 (0x00007f867a399000)        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f867a353000)        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f867a349000)        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f867a343000)        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f867a1f4000)        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f867a1d7000)        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8679fe5000)        /lib64/ld-linux-x86-64.so.2 (0x00007f868e62d000)果不其然 libcusparse.so.12 依赖的 libnvJitLink.so.12 被加载到了系统 CUDA 目录 (/usr/local/cuda/lib64) 下,而不是预定义的 PyTorch 虚拟环境的目录。问题根源:LD_LIBRARY_PATH 优先级(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ echo $LD_LIBRARY_PATH/usr/local/cuda/lib64:至此,问题根源已经明确:LD_LIBRARY_PATH 环境变量导致系统 CUDA 库路径优先于 PyTorch 虚拟环境的 CUDA 库路径被加载。这导致了版本不匹配,PyTorch 无法找到所需的符号。 解决方案:unset LD_LIBRARY_PATH解决这个问题最直接的方法就是移除 LD_LIBRARY_PATH 对系统 CUDA 路径的设置:(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ unset LD_LIBRARY_PATH再次查看 libcusparse.so.12 的动态链接:(modelforger) wangh@ubuntu:~/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib$ ldd libcusparse.so.12        linux-vdso.so.1 (0x00007fff959a7000)        libnvJitLink.so.12 => /home/wangh/codes/ModelForger/.venv/lib/python3.12/site-packages/nvidia/cusparse/lib/./../../nvjitlink/lib/libnvJitLink.so.12 (0x00007f303000e000)        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f302ffc8000)        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f302ffbe000)        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f302ffb8000)        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f302fe69000)        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f302fe4c000)        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f302fc5a000)        /lib64/ld-linux-x86-64.so.2 (0x00007f30443f9000)现在,libnvJitLink.so.12 正确地加载到了 PyTorch 虚拟环境的目录下。验证:问题解决现在,libnvJitLink.so.12 正确地加载到了 PyTorch 虚拟环境的目录下。验证:问题解决最佳实践与总结避免全局设置 LD_LIBRARY_PATH: 在全局环境变量(如 .bashrc 或 .bash_profile)中设置 LD_LIBRARY_PATH 会干扰虚拟环境的独立性。理解动态链接机制: 了解 LD_LIBRARY_PATH 的作用以及动态链接库的加载顺序,有助于快速定位和解决类似问题。
  • [技术干货] python 3.8 的anaconda下载方法【转】
    Python3.8 版本的 Anaconda 下载与安装指南在当今数据科学、机器学习和人工智能领域,Anaconda 作为一款集成了众多 Python 包的发行版,受到了广泛欢迎。它不仅简化了环境管理,还极大地提高了开发效率。本文将详细介绍如何下载并安装包含 Python 3.8 的 Anaconda 发行版,帮助读者快速上手使用这一强大的工具。一、Anaconda 简介Anaconda 是由 Continuum Analytics 公司开发的一个开源项目,是一个用于科学计算的数据分析包集合,包括了许多流行的科学计算包如 NumPy, SciPy, pandas, IPython, matplotlib, scikit-learn 等。同时,Anaconda 提供了一个名为 conda 的包管理器以及环境管理系统,使得用户可以非常方便地安装这些包,并且可以轻松创建不同的环境来隔离不同项目之间的依赖关系。二、下载 Anaconda打开浏览器 并访问 Anaconda 官方网站在首页上找到 “Download Anaconda” 部分,点击进入下载页面。选择合适的版本进行下载:对于大多数个人用户而言,Anaconda Individual Edition 即可满足需求;根据操作系统(Windows/Mac/Linux)选择对应的安装程序;在版本选择方面,由于我们的目标是安装 Python 3.8,请务必确认所选安装包支持该版本。注意:Anaconda 官网提供的最新版可能已经更新到了更高版本的 Python。如果直接下载最新版但没有明确指定 Python 3.8,则可能会自动安装较新的 Python 版本。因此,在下载前最好先检查一下安装包的具体信息,或者直接通过 Anaconda Navigator 手动设置 Python 版本。三、安装 AnacondaWindows 系统下载完成后运行 .exe 文件,开始安装向导。一路点击 “Next” 直到看到 “Advanced Options” 页面,在这里可以根据需要选择是否添加 Anaconda 到 PATH 环境变量,建议勾选以方便后续操作。在 “Install for” 选项中选择 “Just Me” 或 “All Users”,前者只对当前账户生效,后者则对所有系统账户都可用。继续点击 “Next” 直至完成安装。macOS 系统双击下载好的 .pkg 文件,启动安装助手。按照提示完成安装步骤,过程中同样可以选择是否更新系统路径。Linux 系统打开终端,切换到下载目录,执行以下命令:1bash Anaconda3-2021.11-Linux-x86_64.sh按照脚本提示完成安装过程。为使 Anaconda 生效,需要更新 .bashrc 或者 .zshrc 文件(取决于使用的 shell),添加如下内容:1export PATH="/home/yourname/anaconda3/bin:$PATH"最后,重新加载配置文件或重启终端即可。四、验证安装结果无论在哪种操作系统上完成安装后,都可以通过终端(或命令行)输入 conda --version 和 python --version 来验证是否成功安装 Anaconda 及其携带的 Python 版本。五、设置 Python 3.8 作为默认版本假设已经按照上述方法正确安装了 Anaconda,但默认安装的 Python 版本并不是我们想要的 3.8,此时可以通过以下步骤来调整:使用 conda env list 查看所有已创建的环境。如果没有 Python 3.8 的环境,可以创建一个新的环境:1conda create -n py38 python=3.8激活刚刚创建的环境:1conda activate py38检查当前激活环境中 Python 的版本:1python --version输出结果应为 Python 3.8.x。为了以后能够更加方便地切换环境,可以考虑利用别名功能。例如,在 .bashrc 或者 .zshrc 中添加一行命令:1alias py38="conda activate py38"这样每当我们想要使用 Python 3.8 时只需输入 py38 就能快速切换到相应的环境。
  • [技术干货] Python实现批量Excel拆分功能【转】
    在日常办公中,我们经常需要将包含多个Sheet页的Excel文件拆分成多个独立的Excel文件。例如,当我们要把一份Excel表格发给各部门确认时,出于控制信息知悉范围、确保数据保密性等方面的考虑,每个部门仅需查看和确认与自己部门对应的Sheet页。手动拆分Excel文件非常繁琐耗时,为了提高效率,我们可以使用Python编写一个自动化小工具,批量拆分Excel文件中的每个Sheet页为独立的Excel文件。本文将分享如何使用Python实现批量Excel拆分的功能,并提供详细的代码解释。1. 需求分析保持原始Sheet页格式: 在拆分过程中,需要保证每个独立Excel文件中的内容格式与原Excel文件中对应Sheet页的格式完全一致,包括字体样式、单元格格式、颜色设置、对齐方式等,避免因格式丢失影响数据的查看和分析。输出文件管理: 将拆分后的独立Excel文件统一存放到指定的输出文件夹中,便于管理和查找。2. 安装依赖库在开始编写代码之前,我们需要安装一些必要的 Python 库。这里我们将使用 pywin32 库来操作Excel文件,使用 tqdm 库来显示拆分进度。你可以通过以下命令进行安装:1pip install pywin32 tqdm 3. 代码实现以下是完整的Python代码,用于批量拆分Excel文件中的每个Sheet页为独立的Excel文件。代码中包含了详细的中文注释,方便大家理解。3.1 sheet2excel.pyimport osimport shutilimport win32com.clientfrom tqdm import tqdmdef sheet2excel(input_excel_path, output_path):    """    将Excel文件中的每个Sheet页拆分为独立的Excel文件    :param input_excel_path: 输入的Excel文件路径    :param output_path: 输出的文件夹路径    """    # 获取当前脚本所在的目录    parent = os.path.dirname(os.path.realpath(__file__))        # 初始化Excel应用程序    excel = win32com.client.Dispatch("Excel.Application")    excel.Visible = False  # 不显示Excel界面    # 输出文件夹存在则删除重新创建    output_dir_path = os.path.join(parent, output_path)    if os.path.exists(output_dir_path):        shutil.rmtree(output_dir_path)    os.makedirs(output_dir_path)        try:        # 打开Excel文件        wb = excel.Workbooks.Open(os.path.join(parent, input_excel_path))        # 遍历每个Sheet页        for sheet in tqdm(wb.Sheets, desc="EXCEL拆分"):            # 复制当前Sheet页到一个新的工作簿            sheet.Copy()            # 保存新的工作簿为独立的Excel文件            excel.ActiveWorkbook.SaveAs(os.path.join(output_dir_path, f"{sheet.Name}.xlsx"))            # 关闭新的工作簿            excel.ActiveWorkbook.Close()        # 关闭原始工作簿        wb.Close()    finally:        # 退出Excel应用程序        excel.Quit()if __name__ == "__main__":    # 示例:拆分当前目录下的example.xlsx文件,输出到output文件夹    sheet2excel("example.xlsx", "output")3.2 代码说明1. 函数定义与路径处理:sheet2excel 函数接收两个参数:input_excel_path(输入的 Excel 文件路径)和 output_path(输出的文件夹路径)。通过 os.path.dirname(os.path.realpath(__file__)) 获取当前脚本所在的目录,再使用 os.path.join 函数将相对路径转换为绝对路径,确保在不同操作系统上都能正确处理文件和文件夹路径。2. Excel 应用程序初始化:win32com.client.Dispatch("Excel.Application"):初始化 Excel 应用程序对象,用于后续对 Excel 文件的操作。excel.Visible = False:将 Excel 应用程序设置为不可见,避免在后台打开 Excel 界面,减少对用户操作的干扰。3. 输出文件夹处理:shutil.rmtree(output_dir_path):若输出文件夹已经存在,则删除该文件夹及其包含的所有内容,确保输出文件夹为空,避免文件冲突。os.makedirs(output_dir_path):创建新的输出文件夹,用于存放拆分后的独立 Excel 文件。4. 文件拆分操作:wb = excel.Workbooks.Open(...):打开指定的 Excel 文件。for sheet in tqdm(wb.Sheets, desc="EXCEL 拆分"):使用 tqdm 库遍历 Excel 文件中的每个 Sheet 页,并显示拆分进度。sheet.Copy():将当前 Sheet 页复制到一个新的工作簿中。excel.ActiveWorkbook.SaveAs(...):将新的工作簿保存为独立的 Excel 文件,文件名以原 Sheet 页的名称命名。excel.ActiveWorkbook.Close():关闭新的工作簿。wb.Close():关闭原始的 Excel 工作簿。5. 资源释放:excel.Quit():退出 Excel 应用程序,释放相关资源。4. 运行示例假设我们有一个名为example.xlsx的Excel文件,其中包含三个Sheet页:Sheet1、Sheet2和Sheet3。我们可以通过以下代码将每个Sheet页拆分为独立的Excel文件,并保存到output文件夹中:12if __name__ == "__main__":    sheet2excel("example.xlsx", "output")运行上述代码后,output文件夹中将生成三个独立的Excel文件:Sheet1.xlsx、Sheet2.xlsx和Sheet3.xlsx。在拆分过程中,你可以在控制台看到拆分进度的显示,方便了解拆分工作的进展情况。5. 注意事项Excel 版本兼容性:此代码基于 pywin32 库操作Excel文件,需要确保你的系统中安装了Microsoft Excel软件,并且代码在不同版本的 Excel上可能存在兼容性问题。建议在运行代码前,先在小范围数据上进行测试。输出文件夹权限:确保运行代码的用户对输出文件夹具有读写和删除权限,否则可能会导致无法正常创建或删除输出文件夹。数据备份:在执行拆分操作前,务必对原始Excel文件进行备份,以防在拆分过程中出现意外情况导致数据丢失或损坏。6. 总结通过本文介绍的Python代码,我们可以轻松实现批量拆分Excel文件的功能。这种方法不仅提高了工作效率,还减少了手动操作带来的错误风险。
  • [技术干货] Python中常用的四种取整方式分享【转】
    引言在数据处理和数值计算中,取整操作是非常常见的需求。Python 提供了多种取整方式,涵盖了向零取整、向下取整、向上取整和四舍五入等场景。不同的取整方式适用于不同的需求,例如对范围的限制、舍入精度控制等。本文将详细介绍 Python 中这四种取整方式的实现方法及其使用示例,帮助大家在实际开发中选择合适的取整策略,提升代码的精确性向零取整(Truncate)向零取整是指将小数部分截掉,结果总是趋向于零。Python 中的 int() 函数和 math.trunc() 函数都可以实现这一操作。示例代码:import math# 正数向零取整print(int(3.9))          # 输出: 3print(math.trunc(3.9))   # 输出: 3# 负数向零取整print(int(-3.9))         # 输出: -3print(math.trunc(-3.9))  # 输出: -3int() 和 math.trunc() 的区别在于:int() 同时可以将字符串类型的整数转换为整数类型,而 math.trunc() 仅用于截断小数部分。向下取整(Floor)向下取整,也称为地板取整,意味着将数值向下舍入到小于等于该值的最大整数。Python 提供了 math.floor() 函数来实现这一操作。示例代码:import math# 正数向下取整print(math.floor(3.9))   # 输出: 3# 负数向下取整print(math.floor(-3.9))  # 输出: -4向下取整对于负数结果更小,通常用于对连续范围进行离散化,或在特定情况下生成不大于指定值的整数。向上取整(Ceil)向上取整也称为天花板取整,它将数值向上舍入到大于等于该值的最小整数。可以使用 math.ceil() 函数来完成。示例代码:import math# 正数向上取整print(math.ceil(3.1))    # 输出: 4# 负数向上取整print(math.ceil(-3.1))   # 输出: -3该方法用于确保不小于指定数值的离散整数,通常在需要向上保留的场景中使用。四舍五入(Round)四舍五入是最常见的取整方式,在 Python 中,round() 函数提供了这种功能。四舍五入将小数部分大于等于 0.5 的值向上舍入,小于 0.5 的值向下舍入。示例代码:# 四舍五入print(round(3.5))       # 输出: 4print(round(3.4))       # 输出: 3# 负数四舍五入print(round(-3.5))      # 输出: -4print(round(-3.4))      # 输出: -3round() 函数在四舍五入到指定的小数位数时也很有用,比如 round(3.456, 2) 会将数值保留两位小数并输出 3.46。四种取整方式的对比取整方式Python 实现特点向零取整int()、math.trunc()截断小数部分,向零方向取整向下取整math.floor()向负无穷取整,负数更小向上取整math.ceil()向正无穷取整,正数更大四舍五入round()基于四舍五入规则调整整数
  • [技术干货] Python自动化处理手机验证码【转】
    手机验证码(SMS Verification Code) 是一种常见的身份验证手段,广泛应用于用户注册、登录、交易确认等场景。自动化处理手机验证码在数据抓取、自动化测试、批量注册等应用中具有重要意义。然而,需要注意的是,未经授权的自动化获取和使用验证码可能违反相关法律法规和网站的使用条款。因此,在进行相关操作时,请确保遵守法律法规,并获得必要的授权。本文将详细介绍如何使用Python自动化处理手机验证码,包括以下内容:​获取手机验证码​​解析和提取验证码​​自动化输入验证码​​实际应用中的注意事项一、获取手机验证码1.1 通过短信接收验证码最常见的获取方式是通过短信接收验证码。自动化处理的关键在于如何自动读取短信内容。1.2 使用第三方短信接收服务一些第三方服务(如Twilio、Nexmo等)提供API接口,可以接收和读取短信内容。这些服务通常需要注册账号并获取API密钥。示例:使用Twilio接收短信from twilio.rest import Client# Twilio账户信息account_sid = 'YOUR_ACCOUNT_SID'auth_token = 'YOUR_AUTH_TOKEN'client = Client(account_sid, auth_token)# 获取最新的一条短信message = client.messages.list(limit=1)[0]print(f"验证码: {message.body}")# 提取验证码(假设验证码是 6 位数字)import reverification_code = re.search(r'\b\d{6}\b', latest_message).group()print(f"提取的验证码: {verification_code}")1.3 使用ADB读取手机短信通过Android Debug Bridge(ADB)可以读取连接设备上的短信内容。步骤:​连接手机并启用USB调试。安装ADB工具并配置环境变量。使用ADB命令读取短信。示例代码:import subprocessimport redef get_sms_verification_code():    # 使用ADB命令读取短信    result = subprocess.run(['adb', 'shell', 'content', 'query', '--uri', 'content://sms/inbox'], capture_output=True, text=True)    messages = result.stdout.splitlines()        # 正则表达式匹配验证码(假设验证码为4-6位数字)    pattern = re.compile(r'验证码[::]\s*(\d{4,6})')    for message in messages:        match = pattern.search(message)        if match:            return match.group(1)    return Nonecode = get_sms_verification_code()if code:    print(f"获取到的验证码: [code]")else:    print("未找到验证码")1.4 通过API获取验证码某些应用或网站提供API接口,可以直接获取验证码。这种方式通常需要开发者权限或特定的访问密钥。示例:​import requestsdef get_verification_code(api_url, api_key):    headers = {        'Authorization': f'Bearer {api_key}'    }    response = requests.get(api_url, headers=headers)    if response.status_code == 200:        data = response.json()        return data.get('code')    else:        print(f"获取验证码失败: {response.status_code}")        return Noneapi_url = 'https://api.example.com/get_code'api_key = 'YOUR_API_KEY'code = get_verification_code(api_url, api_key)if code:    print(f"获取到的验证码: [code]")1.5 通过邮件接收验证码使用 IMAP 协议读取邮件1、安装 imaplib 和 email 库(Python 自带)。2、使用以下代码读取邮件并提取验证码:import imaplibimport emailimport re# 邮箱配置email_user = 'your_email@example.com'email_pass = 'your_email_password'imap_server = 'imap.example.com'# 连接到邮箱mail = imaplib.IMAP4_SSL(imap_server)mail.login(email_user, email_pass)mail.select('inbox')# 搜索最新邮件status, messages = mail.search(None, 'ALL')latest_email_id = messages[0].split()[-1]# 获取邮件内容status, msg_data = mail.fetch(latest_email_id, '(RFC822)')raw_email = msg_data[0][1]msg = email.message_from_bytes(raw_email)# 提取邮件正文if msg.is_multipart():    for part in msg.walk():        content_type = part.get_content_type()        if content_type == 'text/plain':            body = part.get_payload(decode=True).decode()            breakelse:    body = msg.get_payload(decode=True).decode()# 提取验证码(假设验证码是 6 位数字)verification_code = re.search(r'\b\d{6}\b', body).group()print(f"提取的验证码: {verification_code}")二、解析和提取验证码在获取到验证码后,通常需要对其进行解析和提取。这一步骤取决于验证码的格式和传输方式。2.1 正则表达式提取使用正则表达式从短信或其他文本中提取验证码。import redef extract_code(text):    pattern = re.compile(r'验证码[::]\s*(\d{4,6})')    match = pattern.search(text)    if match:        return match.group(1)    return Nonetext = "您的验证码是:123456,请在5分钟内使用。"code = extract_code(text)print(f"提取到的验证码: [code]")2.2 JSON解析如果验证码通过API以JSON格式返回,可以使用json模块解析。import jsondef parse_json_code(json_data):    data = json.loads(json_data)    return data.get('code')json_data = '{"code": "654321", "expiry": 300}'code = parse_json_code(json_data)print(f"解析到的验证码: [code]")三、自动化输入验证码获取并提取验证码后,可以将其自动输入到目标应用或网站中。这通常涉及模拟用户操作,如填写表单、点击按钮等。3.1 使用Selenium自动化Web应用示例:自动登录并输入验证码from selenium import webdriverimport time# 初始化浏览器驱动driver = webdriver.Chrome(executable_path='path/to/chromedriver')# 打开登录页面driver.get('https://example.com/login')# 输入用户名和密码driver.find_element_by_id('username').send_keys('your_username')driver.find_element_by_id('password').send_keys('your_password')# 获取验证码并输入code = get_sms_verification_code()  # 使用前述方法获取验证码driver.find_element_by_id('verification_code').send_keys(code)# 提交表单driver.find_element_by_id('login_button').click()# 等待登录完成time.sleep(5)# 关闭浏览器driver.quit()3.2 使用Appium自动化移动应用示例:自动填写移动应用中的验证码from appium import webdriverimport timedesired_caps = {    'platformName': 'Android',    'deviceName': 'YourDeviceName',    'appPackage': 'com.example.app',    'appActivity': '.MainActivity',}driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)# 等待应用加载time.sleep(5)# 输入验证码code = get_sms_verification_code()driver.find_element_by_id('com.example.app:id/verification_code').send_keys(code)# 提交验证码driver.find_element_by_id('com.example.app:id/submit_button').click()# 等待操作完成time.sleep(5)driver.quit()
  • [技术干货] 使用Python实现文件重命名的三种方法【转】
    1. 随机命名这个方法是将文件夹中特定类型文件随机命名,下图是文件原始名称随机重命名代码如下: def fun1(filePath):    """    重命名函数fun1    输入:文件夹路径    功能:对文件夹中的全部文件进行随机命名    """    suffix = '.txt'  # 设置后缀,筛选特定文件以更改名称    for file in os.listdir(filePath):        if file.endswith(suffix):            name = file.split('.')[0]            suffix = file.split('.')[1]            salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))  # 随机输出8位由英文字符和数字组成的字符串            newname = name.replace(name, salt)            os.rename(os.path.join(path, file), os.path.join(path, newname + '.' + suffix))    print("End")2. 基础名+数字序号但是我想将其改成统一的命名,那么就用这种重命名方法代码如下:def fun2(path):    """    重命名函数fun2    输入:文件夹路径    功能:对某一个文件夹中的某一类文件进行统一命名,命名格式为:基础名+数字序号    """    i = 1    suffix = '.txt'  # 设置后缀,筛选特定文件以更改名称    for file in os.listdir(path):        if file.endswith(suffix):            if os.path.isfile(os.path.join(path, file)):                new_name = file.replace(file, "name_%d" % i + suffix)  # 根据需要设置基本文件名                os.rename(os.path.join(path, file), os.path.join(path, new_name))                i += 1    print("End")3. 特定字符替换假如我的文件中都包含相同的字符(如示例中都包含name),但是我想将其更换为别的字符,那么就用这个方法。代码如下:def fun3(filePath, old_text, new_text):    """    重命名函数fun3    输入:文件夹路径、需替换的字符、替换后字符    功能:对文件名中的特定字符进行替换    """    for i, j, k in os.walk(filePath):        for name in k:            newName = name.replace(old_text, new_text)            name = i + "\\" + name            newName = i + "\\" + newName            os.rename(name, newName)    print("End")
  • [技术干货] python安装whl包并解决依赖关系的实现【转】
    一、什么是whl文件?whl是一种预编译的二进制包文件,它主要用于安装python库。简单来讲whl就是一种已经编译好的python库文件。我们可以使用whl包来安装python库。二、我们为什么需要使用whl文件来安装python库?有的小伙伴可能会疑惑,我们安装python库时使用“pip install [库名]”来安装一个python库,这样可以直接借助网络将这个库的包拉下来并且将这个库的依赖项也一并拉取下来。拉取下来以后pip还会帮我们解决这些库的依赖问题,这样的方法明明很方便,为什么我们还需要使用whl包来安装python库?其实,使用whl一般用于一些很特殊的情况,比如在公司的内部服务器中,这些服务器是不允许连接网络的;亦或是我们使用pip命令安装库时,即使换源了,但是下载依旧很慢。遇到这些情况时,我们大概率都是把要安装的包下载下来再安装。三、我们应该去哪儿下载whl包?我们可以去到python官方的第三方软件库“pypi”,它是一个中央存储库,开发者可以在这里上传他们的软件包,而其他开发者可以下载并使用这些软件包。所以,我们接下来会演示如何在pypi中下载一个库并且解决它的依赖关系最后安装它。四、下载whl包我们可以直接在浏览器中搜索“pypi”。五、whl包的安装我们在powershell中将路径切换到这个放有whl包的文件夹,我们切换到这个文件夹以后可以使用“ls”命令查看这个目录下的文件,如果你使用“ls”没有看到这个文件,哪怕出现了再多的文件都意味着你的路径错误了。请将下载的文件放到一个你能找到的位置再使用powershell把路径切换过去,或者使用绝对路径。我们可以使用下面的命令来安装一个whl包:1pip install [包名]如果你被提示pip命令找不到,你需要先安装pip命令。但是现在应该都不会出现这种情况,在python较新的版本中,python被安装时就附带了pip。我这里的包名是“pygame-2.6.0-cp38-cp38-win_amd64.whl”所以我会使用“pip install pygame-2.6.0-cp38-cp38-win_amd64.whl”来安装这个包。值得注意的是,这里因为我的包就在这个目录下我才直接输入了包名,如果这个包不在这个目录,我就应该输入别的路径。六、在解决依赖关系后来安装whl包我们现在先来看在线状态pip包管理器是怎么解决依赖关系的。在在线状态下,如果我们使用pip安装包,不管这个包是被下载好的还是说这个包在网络上,我们希望pip自动来安装。pip都是会去网络上下载包。如果你把一个whl包下载到了本地,pip会在安装它时查看它依赖的包,如果它依赖了没有安装的包,pip就会去网络上下载对应的whl文件并且安装它,pip会一直重复这个过程,缺少什么就安装什么,直到把你想要安装的python包给安装好。
  • [技术干货] Python轻松实现批量邮件自动化详解【转】
    在日常工作和生活中,我们经常需要发送邮件,比如批量通知、营销推广、日报自动发送、服务器告警提醒等。手动发送邮件不仅繁琐,而且容易出错。幸运的是,Python提供了强大的smtplib和email模块,可以实现邮件的自动化发送,无论是纯文本邮件,还是带附件、HTML格式的邮件,都能轻松搞定。本文将详细介绍如何使用Python批量发送邮件、添加附件、发送HTML邮件,并结合schedule实现定时邮件发送,让你的工作更智能、更高效。一、环境准备与基础操作1. 安装必要库Python自带的smtplib和email模块无需额外安装,但如果你需要定时发送邮件,可以安装schedule库。安装命令如下:1pip install schedule2. 配置邮箱以QQ邮箱为例,登录QQ邮箱后,在设置中找到“账户”选项,开启POP3/SMTP服务,并获取授权码(用于代替密码)。其他邮箱的配置过程大同小异,一般需要开启SMTP服务并生成授权码。3. 发送简单邮件下面是一个发送简单文本邮件的示例代码:import smtplibfrom email.mime.text import MIMEText def send_email(subject, content, to_addr):    # 邮件配置    from_addr = 'your_email@qq.com'    password = 'your_authorization_code'  # 授权码     # 创建邮件内容    msg = MIMEText(content, 'plain', 'utf-8')    msg['From'] = from_addr    msg['To'] = to_addr    msg['Subject'] = subject     # 发送邮件    try:        server = smtplib.SMTP_SSL('smtp.qq.com', 465)        server.login(from_addr, password)        server.sendmail(from_addr, [to_addr], msg.as_string())        server.quit()        print("邮件发送成功")    except Exception as e:        print(f"邮件发送失败:{str(e)}") # 使用示例send_email('测试邮件', '这是一封测试邮件', 'recipient@example.com')在这段代码中,我们首先导入了必要的库,然后定义了send_email函数,用于发送邮件。在函数内部,我们设置了发件人邮箱、授权码和收件人邮箱,并创建了邮件内容。接着,我们使用SMTP服务器发送邮件,并处理可能的异常。二、邮件内容高级处理1. 发送HTML格式邮件HTML格式的邮件可以包含超链接、图片和自定义样式,使邮件内容更加美观。下面是一个发送HTML格式邮件的示例代码:from email.mime.text import MIMEText def send_html_email(subject, html_content, to_addr):    from_addr = 'your_email@qq.com'    password = 'your_authorization_code'     msg = MIMEText(html_content, 'html', 'utf-8')    msg['From'] = from_addr    msg['To'] = to_addr    msg['Subject'] = subject     try:        server = smtplib.SMTP_SSL('smtp.qq.com', 465)        server.login(from_addr, password)        server.sendmail(from_addr, [to_addr], msg.as_string())        server.quit()        print("邮件发送成功")    except Exception as e:        print(f"邮件发送失败:{str(e)}") # 使用示例html_content = """<h1>月度报告</h1><p>以下是本月的主要数据:</p><ul>    <li>销售额:¥120,000</li>    <li>新增客户:15</li>    <li>客户满意度:95%</li></ul>"""send_html_email('月度报告', html_content, 'manager@example.com')在这段代码中,我们只需要将邮件内容设置为HTML格式的字符串,并将MIMEText的第二个参数设置为'html'即可。2. 使用模板生成邮件内容为了简化邮件内容的编写,我们可以使用模板生成邮件内容。下面是一个使用模板生成HTML邮件内容的示例代码:from string import Templatefrom email.mime.text import MIMEText def generate_email_content(template_file, data):    with open(template_file, 'r', encoding='utf-8') as file:        template = Template(file.read())    return template.substitute(data) # 模板文件示例(template.html)"""<h1>${title}</h1><p>亲爱的${name}:</p><p>${content}</p><p>截止日期:${deadline}</p>""" # 使用示例data = {    'title': '项目进度提醒',    'name': '张经理',    'content': '请及时提交项目进度报告',    'deadline': '2023-10-15'}html_content = generate_email_content('template.html', data)send_html_email('项目提醒', html_content, 'manager@example.com')在这段代码中,我们首先定义了generate_email_content函数,用于从模板文件中读取模板,并使用提供的数据替换模板中的占位符。然后,我们使用示例数据和模板文件生成HTML邮件内容,并调用send_html_email函数发送邮件。三、邮件附件处理1. 添加单个附件在发送邮件时,我们有时需要添加附件,比如PDF、Excel、图片等。下面是一个添加单个附件的示例代码:from email.mime.multipart import MIMEMultipartfrom email.mime.base import MIMEBasefrom email import encoders def send_email_with_attachment(subject, content, to_addr, attachment_path):    from_addr = 'your_email@qq.com'    password = 'your_authorization_code'     msg = MIMEMultipart()    msg['From'] = from_addr    msg['To'] = to_addr    msg['Subject'] = subject     # 添加正文    msg.attach(MIMEText(content, 'plain', 'utf-8'))     # 添加附件    with open(attachment_path, 'rb') as file:        part = MIMEBase('application', 'octet-stream')        part.set_payload(file.read())        encoders.encode_base64(part)        part.add_header('Content-Disposition', f'attachment; filename={attachment_path}')    msg.attach(part)     try:        server = smtplib.SMTP_SSL('smtp.qq.com', 465)        server.login(from_addr, password)        server.sendmail(from_addr, [to_addr], msg.as_string())        server.quit()        print("邮件发送成功,附件已附带!")    except Exception as e:        print(f"邮件发送失败:{str(e)}") # 使用示例send_email_with_attachment('带附件的邮件', '请查收附件', 'recipient@example.com', 'monthly_report.pdf')在这段代码中,我们使用了MIMEMultipart对象来创建邮件,并使用MIMEBase和encoders模块来添加附件。注意,在添加附件时,我们需要将附件文件以二进制模式打开,并读取其内容。2. 批量添加附件如果需要批量添加附件,我们可以对上面的代码进行简单的修改。下面是一个批量添加附件的示例代码:def send_email_with_attachments(subject, content, to_addr, attachment_paths):    from_addr = 'your_email@qq.com'    password = 'your_authorization_code'     msg = MIMEMultipart()    msg['From'] = from_addr    msg['To'] = to_addr    msg['Subject'] = subject     # 添加正文    msg.attach(MIMEText(content, 'plain', 'utf-8'))     # 添加多个附件    for path in attachment_paths:        with open(path, 'rb') as file:            part = MIMEBase('application', 'octet-stream')            part.set_payload(file.read())            encoders.encode_base64(part)            part.add_header('Content-Disposition', f'attachment; filename={path}')        msg.attach(part)     try:        server = smtplib.SMTP_SSL('smtp.qq.com', 465)        server.login(from_addr, password)        server.sendmail(from_addr, [to_addr], msg.as_string())        server.quit()        print("邮件发送成功,多个附件已附带!")except Exception as e:print(f"邮件发送失败:{str(e)}") #使用示例attachment_paths = ['report1.pdf', 'report2.xlsx', 'image.jpg']send_email_with_attachments('带多个附件的邮件', '请查收所有附件', 'recipient@example.com', attachment_paths)在这段代码中,我们只需对attachment_paths列表进行迭代,为每个附件执行相同的添加步骤即可。四、结合schedule实现定时邮件发送使用schedule库,我们可以轻松实现定时邮件发送。下面是一个结合schedule发送定时邮件的示例代码:import scheduleimport time #定时发送邮件的函数def scheduled_email():subject = '定时提醒'content = '这是一封定时发送的邮件'to_addr = 'recipient@example.com'send_email(subject, content, to_addr) #设定每天上午9点发送邮件schedule.every().day.at("09:00").do(scheduled_email) #保持脚本运行,检查并执行定时任务while True:schedule.run_pending()time.sleep(1)在这段代码中,我们首先定义了scheduled_email函数,该函数调用之前定义的send_email函数来发送邮件。然后,我们使用schedule.every().day.at("09:00").do(scheduled_email)来设定每天上午9点执行scheduled_email函数。最后,我们使用一个无限循环来保持脚本运行,并不断检查是否有定时任务需要执行。注意:在实际应用中,直接将脚本放在无限循环中运行可能不是最佳实践。你可以考虑使用操作系统的计划任务功能(如Windows的任务计划程序或Linux的cron作业)来定期运行Python脚本。
  • [技术干货] Python脚本实现图片文件批量命名【转】
    源码批量处理图片尺寸脚本源码import os # 文件管理模块import shutil # 文件复制模块# 定义图片文件批量重命名函数def rename_files(old_path, new_path,prefix,ext=['jpg','png','jpeg','gif','bmp','tif','tiff']):    # 判断新文件夹是否存在,不存在则创建    if not os.path.exists(new_path):        os.makedirs(new_path)    # 原文件夹所有的文件    old_file_list = os.listdir(old_path)    # 遍历所有的文件    for num,file_name in enumerate(old_file_list):        # 跳过非图片文件   去掉下面两行判断条件,则会把所有文件都重命名        if os.path.splitext(file_name)[1][1:] not in ext: # 获取文件扩展名            continue        # 重命名文件        new_file_name = f"{prefix}_{str(num)}{os.path.splitext(file_name)[1]}"        # 构建旧文件和新文件的完整路径        old_file_path = os.path.join(old_path, file_name)        new_file_path = os.path.join(new_path, new_file_name)        # 移动文件        shutil.copy(old_file_path, new_file_path)        print(f"{file_name} -> {new_file_name}")        ### 下面调用函数并传入参数选择路径和文件名前缀# 源文件夹路径old_path = 'new_images'# 新文件夹路径new_path = 'im2'# 文件名前缀prefix = 'heihei'# 调用批量重命名函数rename_files(old_path, new_path, prefix)GUI界面源码import os # 文件管理模块import shutil # 文件复制模块from tkinter import filedialog,messagebox,Label,Entry # 消息框模块,文件选择对话框模块,标签模块,输入框模块import tkinter as tk # GUI模块# 定义图片文件批量重命名函数def rename_files(old_path, new_path,prefix,ext=['jpg','png','jpeg','gif','bmp','tif','tiff']):    # 判断新文件夹是否存在,不存在则创建    if not os.path.exists(new_path):        os.makedirs(new_path)    # 原文件夹所有的文件    old_file_list = os.listdir(old_path)    # 遍历所有的文件    for num,file_name in enumerate(old_file_list):        # 跳过非图片文件   去掉下面两行判断条件,则会把所有文件都重命名        if os.path.splitext(file_name)[1][1:] not in ext: # 获取文件扩展名            continue        # 重命名文件        new_file_name = f"{prefix}_{str(num)}{os.path.splitext(file_name)[1]}"        # 构建旧文件和新文件的完整路径        old_file_path = os.path.join(old_path, file_name)        new_file_path = os.path.join(new_path, new_file_name)        # 移动文件        shutil.copy(old_file_path, new_file_path)        print(f"{file_name} -> {new_file_name}")def rename_images_gui():    # 弹出对话框让用户选择文件夹    old_path = filedialog.askdirectory()    if not old_path:        return    new_path = filedialog.askdirectory(title="选择新文件夹")    if not new_path:        return    # 获取输入框中的值    prefix = entry_prefix.get()    if not prefix:        messagebox.showerror("提示", "请输入文件名前缀")        return  # 如果没有前缀,返回    rename_files(old_path, new_path, prefix)    messagebox.showinfo("提示", "批量重命名完成")def on_rename_button_click():    # 获取输入框中的值    old_path = entry_old_path.get()    new_path = entry_new_path.get()    try:        # 获取将输入框中的值        prefix = entry_prefix.get()    except ValueError:        # 如果输入框中的值不符合格式要求,则弹出错误提示框并返回        messagebox.showerror("提示", "输入格式不符合要求")        return    # 检查输入框中的路径是否有效    if not os.path.isdir(old_path):        # 如果输入框中的路径不是有效目录,则弹出错误提示框并返回        messagebox.showerror("提示", "路径无效")        return    # 调用图片调整函数    rename_files(old_path, new_path, prefix)    # 弹出成功提示框    messagebox.showinfo("Success", "图片批量命名成功")# 创建主窗口root = tk.Tk()# 设置窗口标题root.title("图片批量命名工具")# 创建并放置标签和输入框tk.Label(root, text="储存原图片的文件夹:").grid(row=0, column=0, padx=10, pady=10)# 创建输入框并放置entry_old_path = tk.Entry(root, width=50)# 设置输入框的位置entry_old_path.grid(row=0, column=1, padx=10, pady=10)# 设置按钮点击事件,选择文件夹并将路径插入输入框,如果输入框已有内容,则先清空,再插入,否则直接插入,使用lambda表达式简化代码,tk.Button(root, text="浏览",          command=lambda: entry_old_path.delete(0, tk.END) or entry_old_path.insert(0, filedialog.askdirectory())).grid(    row=0, column=2, padx=10, pady=10)# 创建并放置标签和输入框tk.Label(root, text="储存新图片的文件夹:").grid(row=1, column=0, padx=10, pady=10)# 创建输入框并放置entry_new_path = tk.Entry(root, width=50)# 设置输入框的位置entry_new_path.grid(row=1, column=1, padx=10, pady=10)# 设置按钮点击事件,选择文件夹并将路径插入输入框,如果输入框已有内容,则先清空,再插入,否则直接插入,使用lambda表达式简化代码,tk.Button(root, text="浏览",          command=lambda: entry_new_path.delete(0, tk.END) or entry_new_path.insert(0, filedialog.askdirectory())).grid(    row=1, column=2, padx=10, pady=10)# 创建并放置标签和输入框tk.Label(root, text="文件前缀").grid(row=3, column=0, padx=10, pady=10)# 创建输入框并放置entry_prefix = tk.Entry(root, width=10)# 设置输入框的位置entry_prefix.grid(row=3, column=1, padx=10, pady=10)# 创建并放置调整尺寸按钮rename_button = tk.Button(root, text="运行", command=on_rename_button_click)# 设置按钮的位置rename_button.grid(row=4, column=0, columnspan=3, pady=20)# 运行主循环root.mainloop()打包成.exe可执行文件需要安装python第三方库pyinstaller1pip install pyinstaller在文件所在目录的终端输入下面的命令,就可以把把刚刚的GUI界面打包成一个.exe可执行文件。1pyinsataller filenamefilename是要打包的源文件的名称 比如我要打包我写的图片批量命名的脚本打包成.exe可执行文件,可以在终端使用下面的命令:1pyinstaller study_2.py  .exe可执行文件运行出来的结果和GUI界面是一致的
  • [技术干货] Python中多线程和多进程的基本用法详解【转】
    一、并发编程的主要优势在深入讲解之前,我们先了解一下并发编程的主要优势:提高程序执行速度:多个任务可以同时运行,减少等待时间。提高CPU和I/O资源利用率:多进程可以充分利用多核CPU,多线程可以优化I/O任务。提高程序的响应能力:适用于GUI程序、爬虫、文件处理等场景。二、Python的多线程(Threading)1. 什么是多线程?多线程(Threading)允许程序在同一进程中同时运行多个线程,每个线程都可以执行独立的任务。多线程特别适用于I/O密集型任务,如网络请求、文件读写等。Python提供了threading模块,可以轻松实现多线程编程。2. 多线程示例假设我们有一个任务需要下载10个文件,每个文件的下载时间大约为5秒。如果按照顺序执行,总共需要50秒才能完成所有下载任务。而如果我们使用多线程来同时执行多个任务,就可以大幅度提高执行效率。以下是一个简单的多线程示例代码:import threadingimport time def download_file(file_name):    print(f"开始下载 {file_name}...")    time.sleep(5)  # 模拟下载时间    print(f"{file_name} 下载完成!") files = ["file1.zip", "file2.zip", "file3.zip"]threads = [] for file in files:    thread = threading.Thread(target=download_file, args=(file,))    threads.append(thread)    thread.start() for thread in threads:    thread.join() print("所有文件下载完成!")代码解析:threading.Thread(target=download_file, args=(file,)):创建线程,每个线程执行download_file()函数。thread.start():启动线程。thread.join():等待线程执行完成,确保所有任务完成后再继续执行主程序。3. 多线程的适用场景多线程适用于I/O密集型任务,如爬取网页数据、处理文件读写等。然而,由于Python的全局解释器锁(GIL)限制,多线程在CPU密集型任务(如数学计算、图像处理)中并不能真正实现并行,而是伪并行。因此,对于CPU密集型任务,推荐使用多进程。三、Python的多进程(Multiprocessing)1. 什么是多进程?多进程(Multiprocessing)允许程序同时运行多个进程,每个进程有独立的内存空间,因此可以充分利用多核CPU进行真正的并行计算。多进程适用于CPU密集型任务,如科学计算、数据处理、图像处理等。Python提供了multiprocessing模块来创建多进程。2. 多进程示例以下是一个简单的多进程示例代码,用于计算多个数字的平方:import multiprocessingimport time def compute_square(n):    print(f"计算 {n} 的平方...")    time.sleep(2)  # 模拟计算时间    print(f"{n} 的平方是 {n**2}") numbers = [2, 4, 6, 8]processes = [] for num in numbers:    process = multiprocessing.Process(target=compute_square, args=(num,))    processes.append(process)    process.start() for process in processes:    process.join() print("所有计算完成!")代码解析:multiprocessing.Process(target=compute_square, args=(num,)):创建进程,每个进程执行compute_square()函数。process.start():启动进程。process.join():等待进程执行完成,确保所有任务完成后再继续执行主程序。3. 多进程的适用场景与局限性多进程适用于CPU密集型任务,如复杂数学计算、图像处理、大数据分析等。然而,多进程也有一些局限性:进程创建和管理的开销比线程大。进程间数据共享较复杂,需要使用Queue或Manager。四、线程池与进程池(ThreadPoolExecutor & ProcessPoolExecutor)当需要执行大量任务时,手动创建和管理大量的线程或进程可能会变得非常繁琐。为了方便起见,Python提供了线程池和进程池的功能。1. 线程池示例以下是一个使用线程池下载多个URL内容的示例代码:from concurrent.futures import ThreadPoolExecutorimport timeimport requests def download_url(url):    response = requests.get(url)    return response.content urls = ['http://example.com', 'http://example.org', 'http://example.net'] with ThreadPoolExecutor(max_workers=3) as executor:    results = list(executor.map(download_url, urls)) print("下载完成")在这个示例中,我们使用ThreadPoolExecutor同时下载多个URL的内容,利用线程池减少了创建线程的开销,并提高了下载速度。2. 进程池示例以下是一个使用进程池计算大量数值平方的示例代码:from concurrent.futures import ProcessPoolExecutor def square_number(n):    return n * n numbers = list(range(1000000)) with ProcessPoolExecutor(max_workers=4) as executor:    results = list(executor.map(square_number, numbers)) print("计算完成", list(results)[:10])  # 打印前10个结果以示意
  • [技术干货] python ABC模块介绍
    Python的ABC模块(Abstract Base Classes,抽象基类)是Python标准库中的一个重要组件,它提供了一种基于抽象基类的继承机制,用于实现多态性和代码重用。以下是对Python ABC模块的详细介绍:一、ABC模块的主要功能和组件定义抽象基类:ABC模块包含了一组用于定义抽象基类的ABC类(如abc.ABC)以及一些常用的ABC子类。通过继承abc.ABC类,可以方便地定义抽象基类。抽象方法:使用@abc.abstractmethod装饰器可以声明抽象方法。抽象方法没有具体的实现,必须在子类中实现。如果尝试实例化包含未实现抽象方法的类,将引发TypeError。元类ABCMeta:abc.ABCMeta是一个元类,用于创建抽象基类。它提供了__prepare__和__mro__等方法,用于定义抽象基类的命名空间和确定多重继承顺序。其他装饰器:abc.abstractproperty:定义抽象属性,表示该属性必须在子类中实现。abc.abstractclassmethod:定义抽象类方法,表示该方法必须在子类中实现。abc.abstractstaticmethod:定义抽象静态方法,表示该方法必须在子类中实现。二、ABC模块的使用示例以下是一个简单的示例,演示如何使用ABC模块定义一个抽象基类及其子类:from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return 3.14 * self.radius * self.radius class Square(Shape): def __init__(self, side): self.side = side def area(self): return self.side * self.side # 无法实例化Shape类,因为它包含一个抽象方法area # s = Shape() # 会抛出TypeError # 但可以实例化Circle和Square circle = Circle(5) square = Square(4) print(circle.area()) # 输出: 78.5 print(square.area()) # 输出: 16 在这个例子中,Shape类是一个抽象基类,它包含一个抽象方法area。Circle和Square类继承自Shape类,并实现了area方法。这确保了任何继承自Shape的类都必须实现area方法。三、ABC模块的高级特性虚拟子类机制:一个类可以不通过继承另一个类,但却能被issubclass函数判断为该类的子类。这称为虚拟子类机制。可以通过实现__subclasshook__特殊方法或使用ABC.register方法来实现虚拟子类机制。注册缓存:abc.get_cache_token()用于获取当前的抽象基类(ABC)注册缓存的版本标记。这在动态注册虚拟子类时可能有用,以检测抽象基类的子类关系缓存是否发生了变化。四、总结Python的ABC模块提供了一种强大的机制来定义抽象基类和强制子类实现特定方法。通过使用ABC模块,可以实现多态性、代码重用以及更清晰的类结构。同时,ABC模块还支持虚拟子类机制和注册缓存等高级特性,进一步增强了其灵活性和实用性。