提醒:本文基于ubuntu18.04 ,anaconda3,python3.7
问题描述
我们使用anaconda创建虚拟环境。
conda create -n qq python=3.7 jupyter
conda activate qq
得到虚拟环境前缀(qq),激活成功。
这步是成功了,但是直接运行jupyter notebook的话,并没有使用(qq)环境里的python。
在python中,使用如下命令可以查看
import sys
sys.path
得到
/home/qq/anaconda3/bin/python
可见,使用的还是anaconda的主python环境。
所以import torch,import tensorflow,会报错,提示no module named 'xxx'。
因为anaconda主环境里没装,我们装在了虚拟环境里。
那么,怎么才能让jupyter notebook使用/envs/XXX/环境下的python呢?
方法一 气宗
气宗的核心思想是,不改变anaconda和jupyter的具体结构,而是用一些config的小手段来解决。
1.用anaconda内生插件解决问题
conda install nb_conda
安装完这个牛逼conda之后,再次启动jupyter notebook,就能看到所有虚拟环境都显示出来了。
//参考https://www.jianshu.com/p/afea092dda1d
2.用jupyter插件解决问题
激活环境后,安装ipykernel
conda activate qq
conda install ipykernel
安装好之后,运行如下命令。
python -m ipykernel install --name {你的虚拟环境名字,如qq} --display-name {你想显示的名称}
这个方法,本质上跟方法1是一样的。
原理上来讲,都是在 ......../jupyter/kernels/目录下,创建一个命名为{对应名称}的文件夹,文件夹下放一个kernel.json文件。
于是我们得到....../jupyter/kernels/{对应名称}/kernel.json
运行python -m ipykernel .... 那行命令,就是做创建文件夹和创建文件这两件事情。
在没运行python -m ipykernel ....之前,用find找一下这个文件
find . -name 'kernel.json'
可以看到输出为
./anaconda3/pkgs/ipykernel-5.1.0-py37h39e3cac_0/share/jupyter/kernels/python3/kernel.json
./anaconda3/share/jupyter/kernels/python3/kernel.json
这个/share/jupyter/kernels/python3/kernel.json就是关键了。
我们来看看json文件的内容
{
"argv": [
"/home/qq/anaconda3/bin/python",
"-m",
"ipykernel_launcher",
"-f",
"{connection_file}"
],
"display_name": "Python 3",
"language": "python"
}
正是因为argv中设置的地址为'./anaconda3/bin/python',才导致jupyter的默认kernel为anaconda的主环境。
3.小结
显然,
如果我们在对应的/kernels/目录下,新建一个文件夹,再新建一个kernel.json,
把地址设置为'./anaconda3/envs/qq/bin/python',
就可以用到虚拟环境qq下的python了。
无论是 nb_conda,还是ipykernel,本质上都是在做这件事情。
只不过一个是用anaconda的插件,一个是用jupyter的插件。
对软件实体并没有改变,是为气宗。
//参考https://www.jianshu.com/p/f70ea020e6f9
方法二 剑宗
上面我们想到了用修改kernel.json的方法来实现虚拟环境的利用。
但气宗的方法毫无美学素养,例如安装了牛逼conda,有多少个环境,就全给你丢列表上去了,密密麻麻一大堆显然不好。
还有没有别的思路呢?
很简单,我们注意到,在对气宗的分析里,使用find命令后,有这么一行。
./anaconda3/share/jupyter/kernels/python3/kernel.json
这显然是anaconda主环境的kernel配置文件地址。
那么问题就来了。
为什么默认会调用anaconda主环境呢? 能不能调用虚拟环境的配置文件呢?
我们想到windows下安装anaconda,创建虚拟环境之后,会在开始菜单里给出一个快捷入口。
观察打开方式
得到链接
E:\ProgramData\Anaconda3\python.exe
e:\ProgramData\Anaconda3\cwp.py
e:\ProgramData\Anaconda3\envs\nlp
e:\ProgramData\Anaconda3\envs\nlp\python.exe e:\ProgramData\Anaconda3\envs\nlp\Scripts\jupyter-notebook-script.py
"%USERPROFILE%/"
我们发现,这个快捷方式最终是用\envs\nlp\python.exe,去运行\envs\nlp\Scripts\jupyter-notebook-script.py,达到了在虚拟环境nlp下启动jupyter的目的。
寻找了很久,发现ubuntu下没有Scripts文件夹。
但这不影响我们有一个猜想。
猜想:
只要用\envs\nlp\python,去运行\envs\nlp\jupyter,就可以实现我们的目的。
为了验证猜想,我们用命令查看。
which jupyter notebook
返回值是anaconda主目录的/bin/jupyter。
(qq) qq@qq-Z370-HD3:~$ which jupyter
/home/qq/anaconda3/bin/jupyter
我有一个大胆的想法!
显然,anaconda的结构是这样的。
每个虚拟环境里面的包,可以自己独立安装,互不影响。
即环境env1和env2里可以共存2份numpy。
但是对于jupyter notebook这种核心工具,整个anaconda里是只有一份的。
无论创建多少个虚拟环境virtual env1,2,3,...,n。
运行jupyter notebook时 都是从主环境里调用!
原因是什么?
回到创建虚拟环境qq时的命令,这句话就是说,在虚拟环境qq中,复用主环境的jupyter,节约存储空间。
conda create -n qq python=3.7 jupyter
如果我们不想节约存储空间呢?
直接pip安装个新的
conda activate qq
(qq): pip install jupyter notebook
Successfully installed
再次运行which
(qq) qq@qq-Z370-HD3:~$ which jupyter notebook
/home/qq/anaconda3/envs/qq/bin/jupyter
果然!
在(qq)环境下,单独安装一份新的jupyter,这样默认寻址找到的就是我们的这份jupyter。
运行这份qq环境下的jupyter,默认采用的kernel就是/envs/qq/bin/python了。
运行jupyter。
(qq) qq@qq-Z370-HD3:~$ jupyter notebook
[I 11:48:27.409 NotebookApp] 启动notebooks 在本地路径: /home/qq/anaconda3/envs/qq/bin
[I 11:48:27.409 NotebookApp] 本程序运行在: http://(qq-Z370-HD3 or 127.0.0.1):8888/
[I 11:48:27.409 NotebookApp] 使用control-c停止此服务器并关闭所有内核(两次跳过确认).
为了保险起见再次确认所在环境
import sys
sys.path
['/home/qq/mytrain/',
'/home/qq/anaconda3/envs/qq/lib/python37.zip',
'/home/qq/anaconda3/envs/qq/lib/python3.7',
'/home/qq/anaconda3/envs/qq/lib/python3.7/lib-dynload',
'',
'/home/qq/anaconda3/envs/qq/lib/python3.7/site-packages',
'/home/qq/anaconda3/envs/qq/lib/python3.7/site-packages/IPython/extensions',
'/home/qq/.ipython']
这下可以确定是在虚拟环境下运行的了!
这样一来,就解决了我们的问题。
安装了新的jupyter,根本上改变了物理存储器上的软件,所以称之为剑宗!
尾声与大胆的想法
学完了剑宗,我们再回顾一下气宗的思路。
在安装好qq环境下的新jupyter之后,我们find一下
(qq) qq@qq-Z370-HD3:~$ find . -name 'kernel.json'
./anaconda3/envs/qq/share/jupyter/kernels/python3/kernel.json
./anaconda3/pkgs/ipykernel-5.1.0-py37h39e3cac_0/share/jupyter/kernels/python3/kernel.json
./anaconda3/share/jupyter/kernels/python3/kernel.json
可以看到,多出了第一行/envs/qq/share/jupyter/kernels/。
这个目录,我们就是我们新安装的jupyter的配置文件目录。
你一定很好奇,新的配置文件内容是什么。
内容如下:
{
"argv": [
"python",
"-m",
"ipykernel_launcher",
"-f",
"{connection_file}"
],
"display_name": "Python 3",
"language": "python"
}
我们惊奇的发现,在python位置这一条里,只写了"python" !
只写"python"就可以了吗???
那么我又有了一个大胆的想法。
假设我们不安装这个新的jupyter。
调用的还是anaconda主目录下的jupyter。
我们把主目录的jupyter的配置文件kernel.json,从"xxxxx/bin/python"改成"python"。
这样一来,哪怕我们运行的是主目录的jupyter。
实际上加载的kernel还是"python"。
在哪个虚拟环境下运行jupyter,调用的"python"就是当前虚拟环境下的python!
这种方法不是比创建十几个新文件夹,创建十几个新文件来的有美感多了嘛!
利用剑宗的方法来改革气宗,不知道可不可行。
留给哪位有缘人来做下实验~