Python 常用技巧

1 清理 PIP 缓存

# Credits: https://linuxhandbook.com/clear-pip-cache/
pip cache info # 查看缓存信息
pip cache list # 查找各个包的缓存
pip cache dir # 查找缓存所在的目录
pip cache remove [package_name] # 从缓存中删除特定包
pip cache remove * # 从缓存中删除每个包
pip cache purge # 从 pip 缓存中删除所有内容
sudo rm -rf /root/.cache/pip # 手动删除 pip 缓存
pip install package_name --no-cache-dir # 安装没有缓存的包

2 查看Python库的空间占用

结果示例(部分):

xgboost 2.0.1: 436.63 MB
----------------------------------------
catboost 1.2.2: 298.30 MB
----------------------------------------
httpstan 4.10.1: 214.71 MB
----------------------------------------
llvmlite 0.41.1: 134.52 MB
----------------------------------------
scipy 1.11.3: 96.34 MB

相关代码:

# Credits: https://stackoverflow.com/a/67914559/11067496
sort_in_descending = True   # Show packages in descending order

import os
import pkg_resources
from tqdm import tqdm

def calc_container(path):
    total_size = 0
    for dirpath, _, filenames in os.walk(path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            total_size += os.path.getsize(fp)
    return total_size

dists = [d for d in pkg_resources.working_set]
dists_with_size = {}

for dist in tqdm(dists):
    try:
        path = os.path.join(dist.location, dist.project_name)
        size = calc_container(path)
        dists_with_size[size] = dist
    except OSError:
        '{} no longer exists'.format(dist.project_name)

# Sort packages size
dists_with_size = dict(sorted(dists_with_size.items(), reverse=sort_in_descending))

for size, dist in dists_with_size.items():
    if size/1000 > 1.0:
        print (f"{dist}: {size/1000000:.2f} MB")
        print("-"*40)

3 模块依赖分析

自带工具:pip freeze

  • 支持已有安装模块的依赖分析
  • 支持直接输出requirements.txt

第三方分析工具:<code>pipdeptree</code>

  • 支持已有安装模块的依赖分析(输出格式更人性化)
  • 支持直接输出requirements.txt(还支持其他格式)
  • 支持单个已安装模块的上层依赖分析
  • 分析警告:冲突依赖项和循环依赖

4 终端调试代码

pdb:Python自带的Debug工具

非侵入式:python3 -m pdb filename.py

侵入式:import pdb;pdb.set_trace()

pdb 常用命令:

  • l:查看当前位置前后11行源代码
  • ll:查看当前函数或框架的所有源代码
  • b:查看或设置断点(b lineno;b filename:lineno; b functionname
  • tbreak:添加临时断点(执行一次后自动删除断点;方法同 b
  • cl:清除断点,多个断点以空格为间隔
  • p:打印变量值
  • s:执行下一行(能够进入函数体)
  • n:执行下一行(不会进入函数体)
  • r:执行下一行(在函数中时会直接执行到函数返回处)
  • c:持续执行下去,直到遇到一个断点
  • unt lineno:持续执行下去,直到达到指定行或遇到一个断点
  • interact:启动交互式解释器
  • w: 打印堆栈信息
  • 跳到堆栈上一层:u;跳到堆栈下一层:d
  • q:退出

更多用法:pdb --- Python 的调试器

5 单文件调试

判断当前运行的是主程序还是被导入的模块:

def foo():
    print("foo() from module.py")

if __name__ == '__main__':
    print("module.py is being run directly")
else:
    print("module.py is being imported into another module")
  • 模块化和复用:单个 Python 文件既可以被导入使用,也可以独立运行
  • 测试用例:文件作为主程序运行时执行,不影响作为模块导入的情况
  • 代码清晰:可以清晰区分模块的接口和实现,方便代码理解和维护

6 全局解释器 GIL

GIL 被称为全局解释器锁(Global Interpreter Lock),是 Python 虚拟机上用作互斥线程的一种机制,它的作用是保证任何情况下虚拟机中只会有一个线程被运行,而其他线程都处于等待 GIL 锁被释放的状态。

GIL 的优点

  • 提高单线程程序的执行速度
  • 更易于集成 c 扩展模块

GIL 的缺点:

  • 无法充分利用多核多进程与多线程
  • 多线程资源共享,可能遇到线程安全问题(即同一时刻,必须保证只有一个线程对共享资源进行修改;加锁就是一种同步机制来保证线程安全)

Python 提供了其他方式可以绕过 GIL 的局限,比如使用多进程multiprocess 模块或者采用 C 语言扩展的方式,以及通过 ctypes 和 C 动态库来充分利用物理内核的计算能力。

7 优化导包顺序

项目地址

安装: pip install usort

执行: usort format main.py

优化后的顺序:标准库>第三方库>自定义库或相对引用库

8 自定义模块的安装

python setup.py 作为命令行工具在 setuptools (版本 58.3.0)中已被弃用

Deprecated 已弃用 Recommendation 推荐
python setup.py install python -m pip install .
python setup.py develop python -m pip install --editable .
python setup.py sdist python -m build
python setup.py bdist_wheel python -m build

注意:python -m build 命令需要配合 build 模块使用

参考: Is setup.py deprecated?

9 其他

最全的 pip 使用指南,50 % 你可能都没用过~

一文汇总 Python 可视化工具及图表

往年同期文章