Python模块和包管理
模块和包
在 Python 中每一个 .py 都可以视作一个模块(module)
,而每一个包含 init.py 的目录则可以视作包(packge)
。
如下所示,packs 因为包含 init.py 而可以看做是一个包,而 packs/one.py 则是一个模块
├── main.py
├── packs
│ ├── __init__.py
│ └── one.py
└── readme.md
在 one.py 中简单定义了一个函数 One:
def One():
print("module one")
def OneOne():
print("module one/one")
如果我们想要在main.py中使用的话,那么可以直接import,这种方式也称之为“模块导入”
import packs
packs.one.One()
这里使用的同时加上了模块名称,当然可以省略模块名,而这种方式称之为“成员导入”,这种方式比之前一种方式要快一些
from packs.one import One
One()
当我们运行后就会打印 module one,另外也可以看到在 packs 目录下生成一个 pycache 的新目录,这是编译后中间文件,可以提升模块载入速度。
如果当前模块有多个 One 名称导入的话,可以使用别名进行区分。如果有多个导入名称的话可以使用逗号进行分隔。
from packs.one import One as Alias, OneOne
Alias()
OneOne()
如果要在一行导入的名称过多,也可以分行写
from packs.one import One
from packs.one import OneOne
One()
OneOne()
当然也可以全部导入到当前模块,不过注意这种方式可能存在命名冲突,并且在一些 linter 工具下会提示必须使用全部的导入名称。
from packs.one import *
One()
OneOne()
除了这种全局导入外,还可以在局部作用域导入。
def main():
from packs.one import One
One()
main()
init文件
这里的__init__.py文件每当导入当前包的模块的时候就会运行一次
现在在 packs/init.py 中加入一行 print(“packs one imported”) 的语句,然后运行,可以发现 init.py 是首先运行的
根据这个特点,我们可以再 init.py 输入导出的模块,外部使用的就不需要很长的导入路径了。
修改 packs/__init__py 为如下所示:
from .one import One
print("packs one imported")
那么在 main.py 中就可以这样使用:
from packs import One
One()
或者
import packs
packs.One()
在深入一些,我们在 packs 文件夹下新建一个 two 包,然后修改 main.py 并导入这个包,类如下面
$ tree .
.
├── main.py
├── packs
│ ├── __init__.py
│ ├── one.py
│ └── two
│ ├── __init__.py
│ └── two.py
└── readme.md
2 directories, 6 files
$ cat packs/two/__init__.py
print("packs two imported")
$ cat packs/two/two.py
def Two():
print("module two")
$ cat main.py
from packs.two.two import Two
Two()
可以看到两个 init 都被运行了,但是我们还不能使用 packs.one.One 这个函数,因为在 main.py 并没有导入这个名称。
相对路径和绝对路径引用
上面使用类似这种带有相对路径的导入路径from .XXX,这种代表从当前的xx模块中导入名称,如果想要在packs/two/two.py 中使用上一层的 packs/one.py,就可以使用from ..one import One的方式
# packs/two/__init__.py
from ..one import One
One()
以此类推,那么 … 代表更上一级。
但是这种方式还是有问题的,如果项目深度太大就容易写太多 .,还有一种方式就是绝对路径引用,这里的绝对路径是指相对项目根目录而言的,比如上述例子,那么就要修改为:
# packs/two/__init__.py
from packs.one import One
One()
那引用当前目录的模块必须使用相对路径了,比如上述例子:
# packs/two/__init__.py
from packs.one import One
from .two import Two
One()
注意,这里不能是 from two import Two 的形式!这个也好理解,因为绝对路径不是 . 开始的,如果相对路径不使用 . 开始,那么就得从项目根目录开始找了。
当然绝对路径的模块,就有一个 base 路径,所有的文件都是相对此 base 目录,如果在 IDE 中直接打开这里的模块,模块的根目录就是当前模块,显然就会提示找不到了对应的模块了。
模块搜索顺序
自己写的包名肯定可能和第三方或者标准库同名,不过这种同名通常没有问题。因为python会优先在当前目录搜索然后在环境变量的搜索路径,之后才是标准库和第三方包
这个和linux$PATH的环境变量一样,按照顺序来搜索,一旦导入每个模块就有全局的命名空间,第二层再次加载就会使用缓存
这个路径搜索方式和 nodejs 有些区别,nodejs 是一旦同名,优先标准库,如果自定义一个 http 模块,那么永远不会被加载。
pip包管理工具
Python之所以受欢迎不光是因为它简单易学,更重要的是它有成千上万的宝藏库。这些库相当于是已经集成好的工具,只要安装就能在Python里使用。它们可以处理各式各样的问题,无需你再造轮子,而且随着社区的不断更新维护,有些库越来越强大,几乎能媲美企业级应用。那么这些工具库怎么下载安装呢?它们被放在一个统一的“仓库”里,名叫PyPi(Python Package Index),所有的库安装都是从这里调度。有了仓库之后,还需要有管理员,pip就是这样一个角色。
pip是一个工具,用它可以来管理 Python 标准库中其他的包,允许你安装和管理不属于 Python 标准库的其它软件包,其提供了对 Python 包的查找、下载、安装、卸载等功能。总的来说,pip的Python第三方库的大管家,搞懂它,会让你省很多事。从Python 3 >= Python 3.4 、Python2 >= Python2.7.9 版本开始,pip默认包含在Python的安装程序中,在安装Python时将会自动被安装,省事方便。
*作者:独泪了无痕 链接
包管理
# 安装
# 最新版本
pip install Django
# 指定版本号
pip install Django==2.0.0
# 最小版本
pip install 'Django>=2.0.0'
# 升级包
pip install --upgrade Django
# 卸载包
pip uninstall SomePackage
# 搜索包
pip search SomePackage
# 显示安装包信息
pip show
# 查看指定包的详细信息
pip show -f SomePackage
# 列出已安装的包
pip list
# 查看可升级的包
pip list -o
包依赖项
pip freeze > requirement.txt # 锁版本
pip install -r requirement.txt # 指定安装版本
pip install --user install black # 安装到用户级目录
使用镜像
pip install -r requirements.txt \
–index-url=https://mirrors.aliyun.com/pypi/simple/ \
–extra-index-url https://pypi.mirrors.ustc.edu.cn/simple/
这条命令的意思是从阿里云的镜像源和中国科技大学的镜像源下载 requirements.txt 文件中列出的 Python 包,并安装到当前的 Python 环境中。这种方式可以提高包下载的速度,特别是在网络环境不稳定或者网络延迟较大的情况下。
配置pip镜像
对于windows系统,在C:\Users\文件夹下的用户目录(例如如果当前用户是Administrator则是C:\Users\Administrator)下创建pip文件夹,然后再在此文件夹下创建pip.ini文件,在文件中写入一下内容:
[global]
# 添加默认下载地址,以阿里云源为例
index-url = https://mirrors.aliyun.com/pypi/simple/
[install]
# 此参数是为了避免麻烦,否则使用的时候可能会提示不受信任
trusted-host = mirrors.aliyun.com
配置完成后在通过 pip config list 查看pip配置。
升级pip
pip install -U pip 或者sudo easy_install --upgrade pip
Pyenv
我们经常会遇到这样的开发需求,比如你手头有多个开发项目,其中项目A要求用python3.7,项目B需要用python3.6,有要求项目A和项目B依赖包相互独立,互不干扰。为了满足这样的开发需求,我们需要在自己的电脑上安装多个Python版本,并且项目之间进行环境隔离。因此,我们要想运行这些项目,在工作电脑上就要安装不同版本的Python。pyenv 是Python版本管理工具,通过系统修改环境变量来实现Python不同版本的切换,利用它可以在同一台电脑上安装多个版本的Python,设置目录级别的Python,还能创建和管理vitual python enviroments。而且所有的设置都是用户级别的操作,不需要sudo命令。
安装或升级pyenv
在 Windows 系统下安装 pyenv 需要借助 pyenv-win。pyenv-win 是 pyenv 的一个移植版本,专门针对 Windows 平台。下面是详细的安装步骤:
- 使用 Git 安装
克隆 pyenv-win 仓库:git clone https://github.com/pyenv-win/pyenv-win.git %USERPROFILE%.pyenv
- 配置环境变量 打开系统的环境变量设置界面:
- 右键点击“此电脑”或“我的电脑”,选择“属性”。
- 点击“高级系统设置”。
- 在“系统属性”窗口中,点击“环境变量”。
在“系统变量”部分,找到并编辑 Path 变量,添加以下路径
%USERPROFILE%\.pyenv\pyenv-win\bin
%USERPROFILE%\.pyenv\pyenv-win\shims
保存更改并关闭所有窗口。
-
验证安装 pyenv –version
-
使用pyenv安装python 列出所有可用的 Python 版本 pyenv install –list
安装指定版本的 Python,例如 3.9.7: pyenv install 3.9.7
设置全局默认的 Python 版本 pyenv global 3.9.7
验证 Python 版本 python –version
Pipenv
Pipenv 是 Python 官方推荐的包管理工具,它综合了 virtualenv、pip 和 pyenv 三者的功能,你可以使用 pipenv 这一个工具来安装、卸载、跟踪和记录依赖性,并创建、使用和组织你的虚拟环境。
安装和升级pipenv
pip install pipenv
pip install --upgrade pipenv
为项目建立虚拟环境
进入到项目目录中,通过下面的指令为项目创建虚拟环境 $ mkdir pipenv_demo $ cd pipenv_demo $ pipenv –python 3.9.9 Creating a virtualenv for this project… Pipfile: /Users/dllwh/work/pipenv_demo/Pipfile Using /Users/dllwh/.pyenv/versions/3.9.9/bin/python3 (3.9.9) to create virtualenv… ⠙ Creating virtual environment…Using base prefix ‘/Users/dllwh/.pyenv/versions/3.7.7’ New python executable in /Users/dllwh/.local/share/virtualenvs/pipenv_demo-RYMSREda/bin/python3 Also creating executable in /Users/dllwh/.local/share/virtualenvs/pipenv_demo-RYMSREda/bin/python Installing setuptools, pip, wheel… done. Running virtualenv with interpreter /Users/dllwh/.pyenv/versions/3.7.7/bin/python3
✔ Successfully created virtual environment!
Virtualenv location: /Users/dllwh/.local/share/virtualenvs/pipenv_demo-RYMSREda
上面的操作,给pipenv_demo这个项目初始化了一个 Python 3.9.9 的虚拟环境,并在项目录下生成一个项目依赖包文件 Pipefile。如果系统中没有 3.9.8 版本的Python,pipenv 会调用 pyenv 来安装对应的 Python 的版本。默认地,虚拟环境会创建在 ~/.local/share/virtualenvs目录里面。我们也可以通过 pipenv –venv查看项目的虚拟环境目录。可以通过 pipenv –rm 删除虚拟环境。
用Pipenv管理依赖包
pipenv使用 Pipfile 和 Pipfile.lock 来管理依赖包,并且在使用pipenv添加或删除包时,自动维护 Pipfile 文件,同时生成 Pipfile.lock 来锁定安装包的版本和依赖信息。相比pip需要手动维护requirements.txt 中的安装包和版本,具有很大的进步。
安装依赖包
为项目安装依赖包到虚拟环境中,使每个项目拥有相互独立的依赖包,是非常不错的Python的开发实践。安装依赖包到虚拟环境中的方法: pipenv install pytest
执行完上面的命令后,检查一下是否安装成功: pipenv graph
观察项目的根目录下,又多了一个 Pipfile.lock 文件。这两个文件记录了此项目的依赖包,这两个文件的区别是 Pipfile 中安装的包不包含包的具体版本号,而Pipfile.lock 是包含包的具体的版本号的。如果不想产生 Pipfile.lock 文件,在安装依赖包的时候,加上 –skip-lock 选项即可。 在使用pipenv的时候,常常会安装过程比较慢,这个是因为pipenv创建的 Pipfile 中默认的Pypi源是python官方的 pypi.python.org/simple。
删除依赖包
如果是要删除虚拟环境中的第三方包,执行: pipenv uninstall pytest
安装项目所有的依赖包
用git管理项目时候,要把Pipfile和Pipfile.lock加入版本跟踪。这样clone了这个项目的同学,只需要执行:
pipenv install
就可以安装所有的Pipfile中 [packages]部分列出来的包了,并且自动为项目在自己电脑上创建了虚拟环境。
安装pipefile.lock中的依赖包
上面的方法都是安装Pipfile中列出来的第三方包的最新版本,如果是想安装Pipfile.lock中固定版本的第三方依赖包,需要执行:
pipenv install --ignore-pipfile
安装requirements.txt里面的依赖包
如果项目之前使用requirements.txt来管理依赖的,那么使用pipenv安装所有依赖可以采用类似pip的方法
pipenv install -r requirements.txt
使用虚拟环境开发
虚拟环境创建好了之后,就可以在里面进行开发了。如果在命令行下开发,则在项目目录下执行 pipenv shell,就进入到了虚拟环境中,在这个环境中,已经包含安装过的所有依赖包了,接下来就可以利用这些依赖包进行开发工作了。如果是用Pycharm进行开发,就更简单了,直接用Pycharm打开项目即可。可以从Pycharm中的左侧导航栏里面看到External Libraries显示的是虚拟环境中的Python解释器了。 在虚拟环境中执行开发好的程序,有两种方式,一种是前面提到的先执行pipenv shell进入到虚拟环境后,再执行python程序;另一种方式,则是执行pyenv run,比如在虚拟环境中执行基于pytest框架编写的测试用例,只需要执行下面的命令即可:
pipenv run py.test