当前位置:网站首页>pip 批量完全卸载包
pip 批量完全卸载包
2022-06-26 04:14:00 【白御空】
创作背景
因为我本机环境中安装的第三方库太多了,所以今天我准备把它们都卸载了,但因为太多了,所以不可能手动一个一个来,于是我便写了个小脚本,本文就记录这个脚本的作用及使用。
如果觉得我这篇文章写的好的话,能不能给我 点个赞 ,评论 、收藏 一条龙(*▽*)。如果要点个 关注 的话也不是不可以。
请各位参加一下文末的 投票 哦,如果 有什么不足之处,还 请各位大佬在评论区提出,不胜感激。
问题分析
要实现上述功能,我们需要解决以下问题:
- 获取所有已安装的包
- 获取每个包的依赖
- 命令行交互,卸载指定包
解决方法
上述三个问题均可以使用 subprocess.Popen 包进行解决。为了方便,第三问题使用 subprocess.run 解决。
网上已经有好多文章都对 subprocess.Popen 和 subprocess.run 的参数进行解释,这里不多赘述。
对于 subprocess.Popen ,除了要执行的命令外,我只设置了 stdin、stdout、stderr 参数。
对于subprocess.run ,除了要执行的命令外,我只设置了如下参数:
- universal_newlines ,设置输入输出的数据类型,True 为字符串,否则为字节串。
- capture_output ,设置是否显示命令执行结果,True 显示,否则不显示。
- input ,这个是关键,使得代码可以与命令行进行交互,即指定命令后,在命令行输入内容执行。在本文中的作用是执行 pip uninstall 【包名】 后输入 y 进行确定。
代码详解
首先导入所需的库:re 、subprocess 。
然后将卸载一个包的代码封装成一个函数,如下(本菜鸡代码水平不足,还请各位大佬指出问题):
def uninstall_completely(name):
# 必备的或不需要卸载的库,可以自行设置
skips = ['pip', 'urllib3', 'setuptools', 'wheel']
if name in skips or name.startswith('-'):
return
print(f'Start to uninstall {
name}')
# 初始化 Popen,读取命令 pip show 【包名】 的执行结果
pipe = subprocess.Popen(f'pip show {
name}', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 如果没有安装该包,则退出
if b'WARNING: Package(s) not found: ' in pipe.stderr.read():
print(f'An error occurred when uninstalling {
name}: {
name} 不存在\n')
return
# 正则匹配获得所有依赖包名
# stdout.read() 的结果是字节串,需要转换为字符串
requirements = ''.join(re.findall('Requires: (.*?)\r\n', pipe.stdout.read().decode()))
print(f"{
name}'s requirements: {
requirements}")
# 关闭命令行
pipe.terminate()
# 卸载指定包
try:
# 执行命令 pip uninstall 【包名】
# 执行命令后需要输入是否卸载 [y/n],因为要卸载,所以指定 input 参数为 'y'
obj = subprocess.run(f'pip uninstall {
name}', universal_newlines=True, capture_output=True, input='y')
# 如果出错,则输出报错原因
if not obj.stderr == '':
print(obj.stderr)
return
# 否则卸载成功
else:
print(f'Uninstall {
name} successfully.')
# 防止中途报错导致程序停止运行
except Exception as e:
print(f'An error occurred when uninstalling {
name}: {
e}')
# 输出结果分隔
print('-------------------------------------------')
# 卸载指定包的所有依赖包,递归调用本函数
for _ in requirements.split(', '):
if r == '':
continue
uninstall_completely(_)
调用函数代码如下:
for line in subprocess.Popen('pip list', stdout=subprocess.PIPE).stdout.read().decode().split('\n')[2:]:
name = line.split(' ')[0]
if name == '':
continue
uninstall_completely(name)
其中:
- pip list 可以查看当前安装的所有包。
- .decode() 是因为 stdout.read() 的结果是字节串,需要将其转为字符串。
- [2:] 去除如下图所示的无用行

如果只卸载单个包的话,直接调用函数。
如果卸载部分包的话,遍历列表并分别调用函数。
改 BUG
写代码的时候 BUG 并不少见,但这次挺少的。出错的原因是读取执行结果时编码错误导致。
具体过程为 run 函数中调用 Popen.communicate() 函数,如下:
with Popen(*popenargs, **kwargs) as process:
try:
stdout, stderr = process.communicate(input, timeout=timeout)
except TimeoutExpired as exc:
process.kill()
然后调用 Popen._communicate() 函数,如下:
try:
stdout, stderr = self._communicate(input, endtime, timeout)
except KeyboardInterrupt:
...
又调用 Popen._readerthread() 函数,如下:
self.stdout_thread = threading.Thread(target=self._readerthread,
args=(self.stdout, self._stdout_buff))
看一下 Popen._readerthread() ,如下:
def _readerthread(self, fh, buffer):
buffer.append(fh.read())
fh.close()
此时会从 Popen.stdout 中读取命令执行结果。
再看一下 Popen.stdout 的初始化代码,如下:
self.text_mode = encoding or errors or text or universal_newlines
...
self.stdout = io.open(c2pread, 'rb', bufsize)
if self.text_mode:
self.stdout = io.TextIOWrapper(self.stdout, encoding=encoding, errors=errors)
此时就明了了,如果指定了 encoding 、errors、text、universal_newlines 中任意一个或多个参数,就意味着输出的结果是 字符串 ,而如果没有指定 encoding 参数的话,默认是使用 gbk 编码,如果和环境中的编码方式不一致的话会导致编码报错。
那我们可以修改一下 Popen 的源码,在 subprocess 中第 767 行 self.text_mode 的定义下一行加入如下代码:
if self.text_mode and encoding is None:
encoding = sys.getdefaultencoding()
如果要将字节串转为字符串并且没有指定编码格式的话,就使用环境默认编码。
结尾
有想要一起学习 python 的小伙伴可以 私信我 进群哦。
以上就是我要分享的内容,因为 学识尚浅,会有不足,还 请各位大佬指正。
有什么问题也可在评论区留言。
边栏推荐
- mysql自带的性能测试工具mysqlslap执行压力测试
- Unity移动端游戏性能优化简谱之 以引擎模块为划分的CPU耗时调优
- 外包干了四年,人直接废了。。。
- 线程同步之读写锁
- 線程同步之讀寫鎖
- SQL related knowledge - DDL
- User control custom DependencyProperty
- Question brushing record day01
- Open source! Vitae model brushes the world's first again: the new coco human posture estimation model achieves the highest accuracy of 81.1ap
- What should I do if I don't understand the precious metal indicators
猜你喜欢
![[Flink] Flink source code analysis - creation of jobgraph in batch mode](/img/8e/1190eec23169a4d2a06e1b03154d4f.jpg)
[Flink] Flink source code analysis - creation of jobgraph in batch mode

Sorting out the examination sites of the 13th Blue Bridge Cup single chip microcomputer objective questions

The open software of win10 system is too small. How to make it larger (effective through personal test)

High performance computing center roce overview

Force buckle 515 Find the maximum value in each tree row

Computer network high frequency interview questions

【QT】资源文件导入
![[Flink] Flink batch mode map side data aggregation normalizedkeysorter](/img/c7/611c7207730555b510505d4a8efe3d.png)
[Flink] Flink batch mode map side data aggregation normalizedkeysorter

Wechat applet is bound to a dynamic array to implement a custom radio box (after clicking the button, disable the button and enable other buttons)

Implementation of seven classes of BlockingQueue interface
随机推荐
Analysis of updatechild principle of widget update mechanism of fluent
Tencent Interviewer: How did binder get its system services?
Judge the same value of two sets 𞓜 different values
Implementation of seven classes of BlockingQueue interface
mysql自带的性能测试工具mysqlslap执行压力测试
Binary search method
I/o virtualization technology - vfio
Conditional variables for thread synchronization
軟件調試測試的十大重要基本准則
VHDL设计
In 2022, what professional competitions can college students majoring in automation, electrical engineering and automation participate in?
The style of the mall can also change a lot. DIY can learn about it
What should I do if the 51 SCM board cannot find the device in keil
What are the advantages and risks of paper gold investment
Lua语法讲解
Threejs专用天空盒素材,五种天空盒素材免费下载
What if the serial port fails to open when the SCM uses stc-isp to download software?
Question brushing record day01
After a test of 25K bytes, I really saw the basic ceiling
Understand CGI and fastcgi