Ubuntu系统中的python包管理——以Ubuntu 22.04为例
Ubuntu系统的python包管理——以Ubuntu 22.04为例Ubuntu系统的python包存储在哪里,apt和pip工具怎么管理python包,python包版本冲突为什么发生,如何解决,如何配置python包的路径等等问题,本博文详细讨论了这些问题。看完以后,可能对Ubuntu系统的python包管理有更加清晰和深刻的认识。
Ubuntu系统的python包管理——以Ubuntu 22.04为例
写在前面
如果大家能用conda之类的虚拟隔离环境,建议直接使用虚拟隔离环境,这样包之间的冲突和版本问题基本能直接解决。
如果我们需要使用Ubuntu系统的python包,比如了解python包存储在哪里,apt和pip工具怎么管理python包,python包版本冲突为什么发生,如何解决,如何配置python包的路径等等问题,本博文详细讨论了这些问题。看完以后,可能对Ubuntu系统的python包管理有更加清晰和深刻的认识。
一、Ubuntu系统的Python包
当运行python3 my_script.py或者导入一个包时,Python会按照以下顺序去查找需要的包
1. 当前脚本所在的目录
例如,lbr_with_force_compensation文件夹中的文件结构为
对应的test1.py,test3.py和test2.py文件中的内容如下Fig. 1, Fig. 2和Fig. 3所示。
Fig. 1
Fig. 2
Fig. 3
然后,我们切换到lbr_with_force_compensation这个路径执行test2.py这个脚本(如果不切换到这个路径,或者切换到这个路径的上层路径,系统会提示找不到这个脚本),成功执行的结果如下,
这说明,在使用python3执行Python脚本时,python会自动找到当前执行路径下的python文件。
2. 环境变量PYTHONPATH指定的目录
例如,lbr_with_force_compensation文件夹中的文件结构为
其中test4.py,test5.py和test2.py文件的内容分别如Fig. 4, Fig. 5和Fig. 6所示。
Fig. 4
Fig. 5

Fig. 6
此时,如果我们想要在test2.py脚本中调用test_python_package中的test4.py中的函数,以及调用test_python_package中的子文件夹sub_test_python_package中的test5.py中的函数,如何让python可以找到这些文件呢?
我们切换到test2.py文件的路径下,执行python3 test2.py命令,发现test4.py和test5.py这两个文件并不在test2.py的父目录下,所以python因为找不到test4.py和test5.py文件而报错。
解决方法是通过配置~/.bashrc文件来添加Python包的查找路径,具体方法如下,
步骤一:打开~/.bashrc文件
gedit ~/.bashrc
步骤二:添加python包查找路径
export PYTHONPATH=path_of_your_python_package:$PYTHONPATH
添加结果如下图Fig. 7所示,

Fig. 7
步骤三:刷新~/.bashrc文件(使配置生效)
source ~/.bashrc
完成Python包的路径添加后,使用命令
python3 -c "import sys; print(sys.path);"
来查看现在系统默认查找的Python包路径,执行结果如下图Fig. 8所示,

Fig. 8
按照上述配置好~/.bashrc文件后,我们再切换到test2.py的路径下,执行python3 test2.py,就可以成功导入test4.py和test5.py中的函数(因为test2.py中使用的from test_python_package是在我们添加的路径下面,python可以从我们添加的路径中找到这个文件以及文件夹中的python脚本),执行结果如下图所示。
3. 用户级别的python包存储路径(即~/.local/lib/pythonX.Y/site-packages/)
可以按照下面Fig. 9到Fig. 16来找到这个用户级别的python包存储路径
Fig. 9

Fig. 10

Fig. 11

Fig. 12

Fig. 13

Fig. 14

Fig. 15

Fig. 16
我们可以发现这个文件夹里面有各种各样的python包。
用户使用pip install --user <package_name> 命令安装的python包会被存放在这个路径下,不需要root权限。用户使用pip install <package_name> 安装的python包默认也会装到这个用户级别路径(Python的默认策略是避免污染系统)。如果使用sudo pip install <package_name>,那么Python包就会被安装到系统级别的路径(一般在Ubuntu系统中,使用sudo apt install将包安装到系统级别路径 中,或者使用pip install安装到用户级别路径 中,不建议使用sudo pip install来安装Python包,因为安装的包可能会修改系统级别的Python包,与系统级别的Python包冲突,且sudo pip install安装的包不受apt工具管理,容易破坏系统的稳定性)。
4. 系统级别的python包存储路径(即/usr/lib/python3/dist-packages/)
这个文件夹比较好找,文件夹中的内容如下图Fig. 17所示,
Fig. 17
Ubuntu和Debian系统在设计Python包管理时,为了让所有Python3小版本(比如Python 3.10)共享系统级别安装的包(比如,使用sudo apt-get install 或者 sudo apt install安装的numpy包,这两个命令等价,但是前者一般用于旧的Ubuntu系统),所以系统级别安装的Python包统一放在了/usr/lib/python3/dist-packages路径下,而不是放在某一个特定的版本目录下(比如/usr/lib/python3.10/dist-packages。如果不信,可以去/usr/lib/python3.10路径下检查,你甚至发现连dist-packages文件夹都不存在)。
在我们的Ubuntu 22.04系统中,系统自带的Python版本是Python 3.10。
问题: 那么问题来了,在没有显式的将Python包放在/usr/lib/python3.10/dist-packages/路径下,Python3.10的解释器在运行时如何找到位于/usr/lib/python3/dist-packages中的Python包?
答案是Python 3.10的解释器在运行时会将/usr/lib/python3/dist-packages加入到它的sys.path中,可以在终端输入下述命令验证
python3.10 -c "import sys; print('/usr/lib/python3/dist-packages' in sys.path)"
我们得到的输出结果如下图Fig. 18所示,
Fig. 18
这说明Python 3.10确实能加载/usr/lib/python3/dist-packages路径下的Python包。
二、Python包管理工具
1. apt管理的是系统级的Python包
首先,apt(或apt-get)是Ubuntu系统的高级包管理工具,用于安装.deb包(Debian系统的软件包格式)。
其次,apt管理的是系统级别的软件包,比如系统Python包(如python3-numpy,python3-scipy等)
最后,apt指令安装(安装指令为sudo apt install)的Python包会被放在系统级别的路径下(/usr/lib/python3/dist-packages/)
2. pip管理Python包的工具
首先,pip是Python官方推荐的包管理器,用于安装和管理Python包。
其次,pip指令安装(pip install或pip install --user)的Python包会安装到用户级别的路径下(~/.local/lib/python3.x/site-packages/),不影响系统级别的包。不推荐使用sudo pip install指令来安装Python包,因为会将Python包安装到系统级别路径下(/usr/local/lib/python3.x/dist-packages/),容易覆盖apt安装的Python包,引起Python包依赖混乱。
最后,pip只能管理用pip指令安装的Python包,我们可以使用pip list指令来列出Python环境中可见的pip安装的包(无论是系统级别路径下的还是用户级别路径下的),pip不会也不能管理apt安装的Python包(apt有自己的一套依赖管理系统)。
问题: 现在考虑一个问题,如果apt管理系统级别下的包路径(/usr/lib/python3/dist-packages)中有numpy包,pip管理用户级别下的包路径(~/.local/lib/python3.x/site-packages/)中有scipy包,我们知道scipy包依赖numpy包。当python解释器执行的Python脚本中调用scipy包会找不到numpy包吗?
答案:不会找不到。当运行import scipy时,Python会从用户级别的路径找到pip安装的scipy,scipy再去import numpy,这时如果用户级别路径下没有numpy,Python就会去系统级别路径下找numpy,所以scipy能找到numpy,只要系统级别路径下有numpy,就不会报错“找不到模块”。但是可能会出现版本不兼容的问题,因为scipy的版本时pip管理工具管理的,numpy的版本是apt管理工具管理的,所以完全可能存在版本冲突。(存在版本冲突,我们一般会优先重新安装用户级别路径中的Python包,来兼容系统级别路径中的Python包。)
三、Python脚本的包调用

Fig. 19
如Fig. 19所示,在执行Python脚本时,比如在脚本中导入numpy包,我们可以使用
print("Numpy version used: ", np.__version__)
来查看当前使用的numpy包的版本。
可以使用
print("Numpy path used: ", np.__file__)
来查看当前使用的numpy包的对应的存储路径。系统输出的numpy包的版本和存储路径的结果如下图Fig. 20所示(我们可以发现numpy包存储在系统级别的python包存储路径,即/usr/lib/python3/dist-packages/)。

Fig. 20
当然,对于其它Python包,比如pandas,我们可以使用下述的命令来查看pandas包的版本以及存储路径。
print("Pandas version used: ", pandas.__version__)
print("Pandas path used: ", pandas.__file__)
我们也可以在终端里面直接使用下面的命令直接查看当前环境下使用的Python包的版本和路径,以pandas包为例,
python3 -c "import pandas; print(pandas.__version__); print(pandas.__file__);"
执行结果如下图Fig. 21所示,
我们可以发现pandas包存储在用户级别的python包存储路径(即~/.local/lib/python3.10/site-packages/)。
写在最后
如果上述内容有任何错漏,请留言批评指正,非常感谢。或者有相关的、好的资料推荐,非常欢迎留言推荐。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)