通用知识前导
什么是 Shell 以及 为什么要学 CLI Shell
想要让计算机打开Course.ipynb文件,直接对着计算机喊“打开Course.ipynb”,它不会搭理你,因为它“听不懂”,所以需要一个叫Shell的“中介”将人类的行为转化成计算机能够理解的机械语言,Shell有壳的意思,包裹着操作系统内核Kernel,连接着人和计算机。
GUI Shell:鼠标点击图标时,GUI Shell能够将“点击”转换成机械语言并告诉计算机。
CLI Shell:将“人键入的纯文本命令”转换成机械语言并告诉计算机,需要依托终端Terminal显示输入的纯文本命令和反馈计算机的运行结果。因此,Shell是一个实现人机交互的命令解释器software
CLI Shell是实现人与计算机交互的最原始的方式,通过CLI Shell能让计算机干所有它能干的事情。CIL Shell中能更直接且方便的进行文件管理、环境配置、信息查询…
关键是,Anaconda中管理环境和包有两种方式:一是GUI Navigator,二是在CLI中依托Shell使用conda命令/工具,而Minicanda不包含 Navigator,所以采用第二种使用方法。因此学会一些基本的Shell命令很有必要,也可以为学习Linux打基础
Windows常用的 Shell有:CMD,PowerShell。 学习PowerShell的详细内容参考:PowerShell的官方文档zh-cn
什么是环境变量Environment Variable
计算机环境理解成 实现某个Project运行的所有工具、组件的集合 ,环境变量理解成 环境的一个配置文件 ,环境变量为环境中各部分组件运行提供必要的信息。可以通过GUI或CLI Shell显示环境变量,环境变量分用户级和系统级,CLI中好像把它们放一起输出了
比较重要的环境变量:PATH。CLI Shell中要让计算机运行某个文件,就需要告诉计算机该文件的位置(绝对路径),如果只告诉计算机该文件的名字,那计算机只会从当前工作目录(cwd,current workding directory)和写在PATH的目录中寻找该文件,因此,如果常用某个文件,就可以把文件所在目录添加到PATH中,这样无论该目录是否为cwd,都能只键入文件名就可以打开文件
整体框架
什么是 Python
比如说想让计算机帮忙计算一下1+1,就可以写一个符合Python语法的.py文件,文件的内容就是让计算机一步一步地计算出1+1的结果。但是,计算机并不能直接读懂文件中想让它干的事情,还需要一个Python解释器,将.py文件中的内容一条一条地翻译成计算机能够读懂的机械语言,机械语言再通过驱动变成电信号与计算机交流。
下图是Python解释器的执行模型:它先将.py编译成字节码.pyc文件,然后内部的PVM部分(Python Virtual Machine)循环执行字节码。常用的Python解释器是CPython,即该Python解释器使用C语言编写的,其他的Python解释器本质上是建立在该执行模型上的修改
现状分析
通过对Python执行模型的粗浅了解可知,想通过Python编程语言让计算机帮忙完成某件事情,只需要用某个文本编辑器写一个满足Python语法的解决这件事情的流程,然后将其保存为.py文件,再把这个文件交给Python解释器运行就能得到结果
Python解释器本身提供命令行交互式界面,但只能一条一条语句输入并会直接给出输出(解释器能够在内存中储存之前的变量),即R-E-P-L,这对于完整的Projects不是很方便,将所有的语句写在.py文件中再一起执行会更合适,或者使用IPython一次输入多行语句再运行
在实际中,为了要完成各种不同的Projects,需要用到不同版本的Python、不同的包… 而它们又不能全放在一起否则可能会发生冲突,于是需要一个管理环境和包的工具;为了提高开发效率,又可以直接将文本/代码编辑器、Python解释器、管理环境和包的工具和调试工具…,所以就有如下一些选择:
- Python官网下载的Python:除Python解释器和必要的组件外,里面有pip组件(可以从PyPI上下载第三方py包),idle组件(提供GUI交互,还集成了文本编辑器…既可以一条一条输入然后输出,也可以在文本编辑器中一起输入再保存为.py文件最后统一输出),venv组件(管理虚拟环境)…
- Anaconda/Miniconda:把一个第三方的环境、包管理工具conda和官网的Python打包在一起,conda的作用像pip和venv结合但能做到的更多
- VScode/Spyter…:这些工具能够集成Python解释器、环境和包管理工具、文本编辑器…形成一个集成开发环境IDE(Integrated Development Environment),这样Projects的整个流程都能在一处完成
- …
学习路线
后面的所有内容都是围绕上述的第二种选择展开:
- 学习Python语言。这是核心,不管选择什么方式使用Python编程,本质上都是做 “写Python代码然后运行” 这件事,不同的方式只是让做这件事变得更加方便
- 理解conda管理环境、包的原理,掌握conda工具
- 理解Jupyter架构,掌握JupyterNotebook/JupyterLab Application
学习Conda
Conda是一个管理环境、包的工具软件,它是和一个Python环境(作为Base环境)打包然后一起发布的,有Miniconda和Anaconda两种发行版。Miniconda是一个轻量级的Python发行版,而Anaconda相较于Miniconda带着很多其他用于科学计算的包和工具。
详细内容参考:Anaconda/Miniconda的官网文档zh-cn 和 conda的官网文档zh-cn
Install Miniconda
详细内容参考:Anaconda/Miniconda的官方文档zh-cn中关于安装的部分
Step1
从官网或者清华开源镜像站下载miniconda的安装包(我当时下载的是Miniconda3-py311_24.3.0-0-Windows-x86_64.exe)
下图是官网下载界面,同一版miniconda区分了不同的操作系统和所携带Python版本(一般是最新的三个),最后一列是该安装包的Hash值。如果不是从官网下载的,可以验证下载的安装包是否和官网一致:在PowerShell中输入
Get-FileHash <安装包绝对路径> -Algorithm SHA256
,若显示的Hash值与官网提供的一样说明它与官网的安装包是一致的,反之说明从别处下载的安装包被修改了
Step2
-
Click安装包,然后Click “Next”,再Click “I Agree”
-
推荐选择 “Just Me”(仅为当前用户安装,默认安装地址为
C:\Users\xxx
)
选择 “All Users”,为本机所有用户安装,默认安装地址应该在系统目录下,需要管理员权限(以管理员身份运行打开该安装包)
-
自定义存放miniconda的目录
-
- Create start menu shortcuts(supported packages only) 仅为支持的包(anaconda prompt和anaconda powershell prompt)在开始菜单创建快捷方式。anaconda prompt/anaconda powershell prompt本质上是为一条命令创建的一个快捷方式,后面再细说,这个建议勾选
- Add Miniconda3 to my PATH environment variable 把前面自定义或默认的存放miniconda的目录
xxx\miniconda3
添加进环境变量PATH中,这样子想运行该文件夹中的文件时就只需要在任意的cwd中键入文件名而不需要绝对路径。但会产生的问题是,如果计算机中还安装了其他同个但不同版本的软件例如不同版本的Python,那么当你某个Project需要用的不是miniconda中的而是本机的另一个Python解释器时,此时如果只键入python
而不指定其绝对路径,那么系统只会找PYTH目录中或cwd下的Python解释器,这时候可能会产生错误,因此不建议勾选 - Register Miniconda3 as my default Python3.11 将miniconda中的Python3.11设置成默认的Python3.11,当本机存在多个Python3.11(官网的、不同发行版的)时运行Python3.11,默认运行miniconda中的Python3.11,这个可以勾选
- Clear the package cache upon completion 在安装完成后删除包缓,这个可勾可不勾,没什么影响
用conda安装包的过程:
- 先看包缓存文件夹
xxx\miniconda3\pkgs
中是否有这个包。若有,跳过B;若没有 - 从默认或给定通道中下载包和其他组件到包缓存文件夹中
- 从包缓存文件夹中复制一份该包到该环境的库目录中
xxx\miniconda3\Lib
这样之后若要安装同个包就不用从网上下载,直接在pkgs中复制一份就行,这也是为什么在
conda install xxx
时 可能会出现"The following packages will be downloaded" 一定有"The following NEW packages will be Installed",前者列出需要的但不在pkgs中的包,所以要从网上下载;后者是列出需要安装(复制)到新环境中的所有的包。不同的环境下安装的包也是先下载到该包缓存中,且同种但不同版本的包是独立存在的。删除包缓存并没有什么影响,区别就是下次要安装之前下过的包时需要重新在网上下载 - 先看包缓存文件夹
5. 可勾可不勾,勾选的话,会在安装完成时打开两个网页:一个是conda的官网文档,另一个是Anaconda的官网
Conda原理
对CLI Shell进行conda相关的配置
在CLI Shell中使用conda实现环境隔离的原理在于修改环境变量(包括但不限于PATH)。但是,修改环境变量的操作是Shell级的命令,理论上直接conda命令并不能实现它们,如下图在PowerShell运行 conda activate
:
所以,实际在CLI Shell中使用conda工具前还有一步操作,对要使用的conda工具的Shell进行配置(使得每次打开/关闭该Shell会话时都会自动添加/删除或修改conda相关的环境变量,具体的我没搞清楚),使得该Shell中的conda命令也成为Shell级的命令。具体的,在Linux/Mac OS的Miniconda安装过程中会询问是否conda init,即是否对目前所使用的Shell进行conda初始化(在该Shell的配置文件中写入conda相关的命令,使得每次打开该Shell会话时都会自动配置conda相关的环境变量),但在Windows下的安装过程中没有询问这一步(应该是因为Windows下安装过程都是GUI中进行的,conda也不知道该去初始化哪个Shell)
Windows系统也是可以在Shell中运行conda init脚本的,但是我还没找到这个文件在哪
对于Windows系统,官方推荐使用 Anaconda Prompt/Anaconda PowerShell Prompt快捷方式来使用conda,查看Anaconda Prompt/Anaconda PowerShell Prompt快捷方式的属性发现,它们本质上就是一条命令的快捷方式,以Anaconda PowerShell Prompt为例:
%windir%\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -NoExit -Command "& 'D:\miniconda3\shell\condabin\conda-hook.ps1' ; conda activate 'D:\miniconda3' "
这条命令的意思是 打开PowerShell然后修改执行策略(PowerShell对运行文件比较严格),再运行conda-hook.ps1文件,最后激活base环境(如果常使用Anaconda PowerShell Prompt且不希望每次都默认打开base环境,可以删除 conda activate 'xxx\miniconda3'
如果不直接点击该快捷方式,也可以开个PowerShell然后一步步输入命令实现一样的效果:
- 输入
powershell.exe -ExecutionPolicy RemoteSigned
相当于再开了一个执行策略为RemoteSigned的PowerShell - 输入
xxx\miniconda3\shell\condabin\conda-hook.ps1
运行该脚本,修改Shell配置,添加有关conda的环境变量
如下图所示,左为未对PowerShll进行conda相关配置的环境变量,右为配置后的环境变量,发现二者不一样(所以我才认为对Shell进行conda相关配置的原理是利用该Shell添加或修改conda相关的环境变量)
总的来说,要在CLI Shell中使用conda工具,需要对该Shell进行conda相关的配置,两种方法:一是在某Shell上运行conda init脚本(在该Shell的配置文件中写入自动添加或修改conda相关环境变量的命令),这样之后每次打开该Shell时都会读取该配置文件然后自动添加或修改conda相关的环境变量,使得conda命令能够执行,一劳永逸;二是在某Shell上运行conda-hook脚本,手动地添加或修改conda相关的环境变量,在该Shell会话结束后就会消失,下次要运行conda就需要再重新手动添加。Anaconda PowerShell Prompt/Anaconda Prompt 就是第二中方法的一个快捷方式,不用每次在Shell中手动执行conda-hook脚本
如果不知道conda init脚本在哪,且在安装miniconda过程中没有选中在开始菜单中创建Anaconda Prompt/Anaconda PowerShell Prompt的快捷方式的话,可以运行
xxx\miniconda3\Lib\_nisi.py
文件,就能在开始菜单中创建它们的快捷方式。有关它们的信息(图标和配置文件)在xxx\miniconda3\Menu\
中,所以如果是自己手动删除它们后面又想弄回来的话,也可以根据该目录中的信息自己创建一个
Conda隔离环境的原理
在Shell中进行conda相关的配置后,就能直接在该Shell环境中使用conda命令了。Conda隔离环境的原理在于 修改环境变量PATH和一些其他的环境变量,使得所有相关操作都指向该环境中的相关程序。
conda activate xxx
激活某个环境后,运行的同名程序都只是该环境内的程序,是因为 conda activate
命令能将该环境中的重要目录添加到PATH中,这样后面输入的任何程序名,操作系统会从找到PATH中找具体路径;除此之外,还会修改其他的一些环境变量以配置conda的一些功能,例如告诉conda install要把包装到哪个环境的哪个文件夹里(仅是我的猜测,具体原理还没搞清楚)
下图说明了激活两个不同的环境(base环境和一个虚拟环境)后,二者PATH和其他一些环境变量(未截全)的不同
配置conda
可以通过conda config --set …或者直接修改conda的配置文件来规定conda的一些行为,例如是否默认激活base环境、是否显示前面的提示符、conda的下载通道是什么… 详细内容参考conda的官方文档zh-cn关于配置的部分
常见的配置是修改conda的下载通道(下载包的urls):conda下载第三方包是有默认default-channels的和第三方的下载通道conda-forge…,但这些网站是国外的,数据传输可能会比较慢,因此可以在配置文件中写入指定的清华开源镜像站提供的下载通道的镜像网址来提高传输速度。类似的,也可以依照清华开源镜像站修改pip的默认下载通道
conda的配置文件默认是在 C:\users\xxx\.condarc
,如果没有的话键入 conda config
会在用户主目录下创建它,也可以为指定环境创建环境级的配置文件。conda读取配置信息的优先级:环境变量 > 环境级配置文件 > 用户级配置文件 > 系统及配置文件
但有个问题目前我没弄清楚:为了区分不同环境的conda的配置文件,我为一个虚拟环境建了一个环境级的配置文件
xxx\env\.condarc
并在里面写入了设置环境提示符为’{name}',键入conda config --show/conda config --show-sources/conda config get
都显示读取了该配置文件,但是conda的行为并没有按照环境级配置文件而是按照用户级的配置文件,这可能是因为存在某个环境变量使得conda的配置文件始终指向用户级的那个配置文件,但这可能会造成一些困扰,因为可能有些环境需要特定的conda配置文件。除此之外,对pip进行配置时会把配置信息写进C:\Users\xxx\AppData\Roaming\pip\pip.ini
中,但无论指定的范围是global、user还是site,都只会写进这个文件(但是按pip config -h
的描述,应该是会根据提供的范围参数写入不同的文件中),这会导致不同环境的pip读取的都是同个配置文件,但可能有些环境的pip需要特定的配置文件
学习conda命令
详细内容参考官方文档:conda的官方文档zh-cn关于命令的部分
学习Jupyter
前面的conda是一个帮忙管理环境和包的工具,而从结果角度理解的话,Jupyter就是一个能提供文本/代码编辑器、调试器、文件管理…反正就是帮助更好地写代码(或其他格式文本如markdown)的umbrella project
Jupyter并不是一个具体的包,而是一个大的project的总代号,它包含很多工具。Jupyer不是一个严格意义上的IDE,它没有管理环境和包的能力,因此都是和conda配套用的。Jupyter不像专门写.py程序的,更像是一个笔记软件,在笔记上运行代码,随时记录并能添加其他元素,默认的文件格式是.ipynb而不是.py(当然也能转成.py文件),所以更多用于科学研究
专门写的.py程序多作为一个工具,需要经常的运行,但Jupyer写Python代码更注重一个结果,可能运行一遍就不再运行
详细内容参考:Jupyter的官方文档zh-cn
下载Jupyter
激活一个虚拟环境(不要base环境,base环境在miniconda下载后就不要动它了),然后在 CLI Shell中键入 conda install -c conda-forge Jupyter
然后就会安装一堆jupyter的sub-projects
Jupyter原理
Jupyter脱胎于Ipython,Ipython是对原有的Python环境中的Python解释器进行一个封装,像在外面套层衣服,增强了该Python解释器的交互能力,例如能一次输入多行语句、语法高亮、自动补全、提示符显示执行次数、魔法命令… 详细关于IPython的内容参考:IPython 文档zh-cn
下图是Python解释器的命令行交互式界面和IPython增强的命令行交互式界面
后来在Jupyter中IPython是作为服务端的内核ipykernel
Jupyter是Client-Serve架构,服务端可以在本地也可以在其他计算机上,客户端通过Web技术和服务端交流。启动Jupyter时,Jupyter Serve会提供一个url,客户端浏览器通过它向服务端发送访问请求,Sever收到后发送应用Jupyter Notebook/JupyterLab的数据到客户端,浏览器接收后进行渲染形成所见的网页界面,该界面上可以对文件进行管理(背后过程是客户端发送数据到Serve上,然后Serve让文件管理工具操作)
当打开一个新的.ipynb文件时会同时启动一个内核,一般是ipykernel IPython Kernel(当然也有别的内核,R语言的…),在代码块中输入代码并运行,客户端将数据发送到Serve,Serve交给ipykernel运行,内核运行完后再让Serve把结果传给客户端显示。Markdown Cell中编辑时过程类似,客户端把数据发送给Serve,Serve把数据发给Markdown解析器mistune,它把markdown转化成html再让Serve把结果传给客户端,浏览器能对html进行渲染,就变成渲染后的样子
以上都是胡扯的,对Jupyter的架构我理解的不是清楚,详细内容参考:Jupyter的官方文档zh-cn
配置Jupyter
Jupyter有专门存放它所包含的一些工具的配置文件的目录 C:\Users\xxx\.jupyter
,例如对JupyterNotebook、JupyterLab的配置文件都会放在里面。IPython是Jupyter的内核,但它的配置文件不在该目录中,而是自己建了一个 C:\Users\xxx\.ipython
目录
对Jupyter的某个工具进行配置,可以直接通过命令行修改,也可以在它的配置文件中修改,例如:在有jupyter的虚拟环境中输入 jupyter notebook --generate-config
或者 jupyter lab --generate-config
会在 C:\Users\xxx\.jupyter
目录下创建这两个应用的默认配置文件,常见修改的配置是默认启动的浏览器和jupyter默认的工作目录(如果不修改默认的工作目录的话,那么打开jupyter时的目录会被认为是工作目录),具体的修改内容上网查询。对它们的客户端Web页面的Setting修改则会写进该目录的其他文件中,例如增大/减小字号…
这有个问题我也没弄懂:对Web的一些Setting不管是Notebook还是Lab都是写进JupyterLab的Setting文件中,即修改JupyterNotebook的字号时,JupyterLab的字号也随之修改,它们共用一个Setting
关于Jupyter配置的详细内容参考:Jupyter官网文档zh-cn中Jupyter的通用配置方法
Jupyter的学习内容
对Jupyter的学习应该把重心放在它的客户端应用上,掌握JupyterNotebook/JupyterLab的Web页面提供的功能,菜单栏工具栏有哪些设置,有哪些快捷方式,怎么提高自身编程效率… 对于服务端,主要学习怎么连接远程的计算机或大型机的服务端。
这方面的内容在官网上文档中也有,官方文档中有针对Jupyter的sub-project工具的用户使用文档
目前的问题
使用conda隔离环境和包没什么问题,但问题是conda本身以及环境中的一些包或工具的配置文件总是默认放在用户主目录中 C:\Users\xxx\
,例如conda、idle、ipython、jupyter… 这会使得不同环境中的相同的工具共用同一个配置文件,即没有实现配置文件的隔离,那么可能有些环境中的工具或组件就需要特殊的配置。
虽然,conda和那些工具或组件的配置命令也提供了仅当前环境进行配置或在当前环境中生成一个配置文件的选项,但是我测试过conda和pip并没有效果。只能说幸运的是,我目前还没碰到在多个环境中都要用到某工具,且对于某个环境的该工具需要进行特殊配置。而且目前我修改的一些工具的配置选项都是无足轻重的(conda和pip的下载通道,Jupyter应用的默认打开的浏览器…),所以放在用户目录也无伤大雅(不同环境的pip,jupyter要共享就共享吧)。
当然也有个解决方法,就是要对某个包进行特殊配置前,先把主目录中的该包的配置文件删掉,这样它就会变成默认的配置,然后再进行特殊的配置;之后要再换种配置时,就再删再配置,重复… 总而言之就是每次要用前都重新配置一遍(也可以先把所有可能的配置文件都准备好,要用哪种配置就把哪个文件放入用户主目录中)