用 NodeJS 思想学 Python——搭建开发环境

前言:熟悉前端的小伙伴都知道,NodeJS 的模块管理工具 npm 非常好用,但随着 npm 的升级,它管理模块的逻辑越来越复杂,而且模块安装目录 npm_modules 也极其庞杂,难以管理。终于 NodeJS 之父 Ryan Dahl 受不了了,在于 2017 年创立了 Deno。

如果你既熟悉 NodeJS 又了解 Python ,不难发现他俩长得真像哥们,不过虽然长得很像,但是在配置项目环境方面,两者的难易程度,可不是一个水平的。

对于我们前端,想创建一个项目很简单的,直接一个命令行完事:

npm init

但是在 Python 里面可有的忙了,因为 Python 本身的限制,我们要想创建一个开发项目,首先要解决两个问题:

  1. 因为 pip install module_name 会把模块放到全局,所以首先就要解决,不同项目的开发模块不能相互影响。
  2. 项目开发过程中的环境管理问题,我们需要有类似 package.jsonpackage-lock.json 的文件,虽然 pip 可以通过 freeze 生成 requirements.txt,但是这个文件太简陋了。

所以接下里我会从 Python 开发环境演变的历史角度来梳理下,如何快速创建一个像 NodeJS 项目环境的一个 Python 项目。

版本管理问题

我们知道软件是一直在更新的,但是项目一般在建立,就要确定软件的版本,以后不会随意去更新的,这就导致了,因为年代的问题,不同项目依赖相同软件的不同版本。

前端小伙伴都知道,我们一般都是使用 nvm 来管理 NodeJS 版本的,Python 肯定也有这个工具,它叫什么呢?

pyenv,没错 Python 中使用 pyenv 来进行版本管理。

但是 pyenv 的安装比 nvm 稍微麻烦点,不是安装上就能用了,而且因为墙的问题,下载速度垃圾的要命,我们还的手动解决。

pyenv 安装完成之后,我们还的手动配置下,你可以去官网查看安装教程,pyenv-github。

我这里通过官网的截图给你,说明下我是如何安装成功的。

github.com_pyenv_pyenv.png

在安装之前,我们可以通过 pyenv install -l 来查看 python 的版本,选一个最新的稳定版,然后使用 pyenv install 3.9.1 命令安装。

不过你安装 python 版本的时候,大概率速度可能过慢,根本下载不下来,所以我们需要镜像,先去 淘宝镜像 找到需要的版本,下载 .tar.xz 的那个,例如 Python-3.9.1.tar.xz,接下来的操作按照这个博客的步骤走:

macOS pyenv入门使用记录

如果安装功能,那么在 ~/.pyenv/versions 就能看到了 :

那么我们怎么使用呢?一般有三种使用方式:

# global 全局设置 一般不建议改变全局设置
pyenv global 

# shell 会话设置 只影响当前的shell会话
pyenv shell 
# 取消 shell 会话的设置
pyenv shell --unset

# local 本地设置 只影响所在文件夹
pyenv local 
# 取消 local  本地的设置
pyenv local --unset

总结:版本管理方面,nvm 完胜 pyenv✌️。

接下来解决我们文章开头抛出来的两个问题。

一、不同项目的模块不互相影响

前端在使用 NodeJS 开发的时候,很少会把项目使用到的模块安装在全局环境,基本都是在本地安装使用的,所以只需要维护好本地依赖文件 package.json 就行了。

但在 Python 中使用第三方模块的时候,很鸡肋了,统一安装到全局,没有安装到本地项目文件夹下的概念。这肯定是不行的,如果多个项目的话,项目模块全给弄到全局,每个项目到底依赖哪些模块,不久傻傻分不清楚了嘛。为了解决这个问题, Python 出现了虚拟环境的概念。

虚拟环境 是通过 virtualenv 来创建的,来看下这个模块的简单安装使用。

$ pip install virtualenv # 安装模块
$ virtualenv myvenv # 创建一个虚拟项目
$ source myvenv/bin/activate # source进入该环境,注意此时命令提示符变了,有个(venv)前缀,表示当前环境是一个名为venv的Python环境。
$ deactivate # 使用deactivate命令,退出当前的venv环境。

但在 pip3.3 之后,Python 内置了一个 venv 模块,用法和 virtualenv 没啥区别 ,但省去了我们的安装等待的问题,所以我们只需要简单的一行命令就能创建一个虚拟环境了:

python3 -m venv project # 创建一个项目
# 剩下的命令和 virtualenv 一致

创建完虚拟环境,当我们在项目中,再手动 install 第三方模块的时候,就能保证模块,只安装在项目目录下。

不过,这时你可能会问,如何保证项目移动过程中的模块维护问题,比如新入职的小 B,使用 git 拉完代码如何安装项目模块,启动应用,Python 又没有类似 NodeJS 管理模块的 package.json 文件。

有解决办法,不过挺麻烦,需要我们手动生成一个类似 NodeJS 项目中的 package.json 文件。

pip freeze > requirements.txt

导出模块到文件,其他小伙伴启动项目的时候,只需要:

pip install -r requirements.txt

我告诉大家为什么不使用 pip freeze 这种方式来管理模块,原因很简单,你的小伙伴 pip install -r requirements.txt 之后,本地没有生成虚拟环境,再安装新的模块,就给安到全局了,到时候 pip freeze > requirements.txt 难免会把其他项目的模块生成到到 requirements.txt 里面。这时候你可能会想,我在 install 之前,手动建一个虚拟环境不就行了,确实很棒,但不麻烦吗……

virtualenv 的有个缺点,没法统一管理,所以又出现了 virtualenvwrapper 来统一管理虚拟环境,来看它的安装和使用方式。

1.安装

# windows
pip install virtualenvwrapper-win
# linux
pip install virtualenvwrapper
2.新建虚拟环境

mkvirtualenv testenv
3.虚拟环境中安装库

pip install requests
4.查看虚拟环境中目前存在的库

pip list
5.查看存在的虚拟环境

workon
6.进入虚拟环境

workon + 虚拟环境名称
7.退出虚拟环境

deactivate
8.删除虚拟环境

rmvirtualenv + 虚拟环境名称

熟悉了 virtualenv 和 virtualenvwrapper,那么 pyenv-virtualenv 和 pyenv-virtualenvwrapper ,相信你也知道是干啥的了,pyenv-virtualenv 完全够用了,pyenv-virtualenvwrapper 我基本不怎么用。

对比着 NodeJS,我们知道 nvm 用来管理 NodeJS 版本,pyenv 用来管理 Python 的版本,一个 node_modules 对应一个前端项目,一个 virtualenv 也对应一个 Python 项目。

到此,Python 的模块管理基本上够用了,但是相比 NodeJS 的 npm 机制还是比较鸡肋,比如 npm 开发环境下有开发依赖,生产环境下有生产依赖。所以 Python 的模块管理还需要进一步加强,加强之后就是 pipenv

接下来就是开头提到的第二个问题的解决办法了。

二、终极大杀器 pipenv

可以简单的认为 pipenv === npm

Pipenv 的官网,是我见过最的一个,你看它的 slogan,for Humans(给人用的),这赤裸裸对 Python 的嘲讽,哈哈哈,不过难用也就别怪开发者去吐槽了:

pipenv homesite

来简单看下 pipenv 的安装,如果你不想本地搭建项目,也可以在线体验:https://rootnroll.com/d/pipenv/

# 安装
pip install pipenv
# 查看帮助
pipenv --help
# 查看版本
pipenv --version # pipenv, version 2020.11.15


# 是否安装成功
localhost:~ condorhero$ pip list
Package          Version
---------------- ----------
appdirs          1.4.4
certifi          2020.12.5
distlib          0.3.1
filelock         3.0.12
pip              20.2.3
pipenv           2020.11.15 # this
setuptools       49.2.1
six              1.15.0
virtualenv       20.3.0
virtualenv-clone 0.5.4 # this

接下来看看如何使用 pipenv:

# 新建一个项目并进入
$ mkdir myWeb-py && cd $_
# Create a new project using Python 3.9, specifically:
# 使用 Python 3.9 虚拟化这个项目,这个命令就类似 npm 的 npm init 
$ pipenv --python 3.9
$ pipenv --venv # 查看生成的虚拟环境的位置
/Users/localhostName/.local/share/virtualenvs/myWeb-py-Z_2FicQw

创建成功会在/Users/localhostName/.local/share/virtualenvs/myWeb-py-Z_2FicQw生成虚拟环境,同时在本地生成 Pipfile 文件,Pipfile 为模块管理文件,和 npm 的 package.json 文件功能是一致的,来看下 Pipfile 文件的内容。

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]

[dev-packages]

[requires]
python_version = "3.9"

我来剖析下 Pipfile 文件的内容:

# source 指定下载源,如果你嫌下载速度慢,可以考虑换源,就像 NodeJS 的 npm 换 cnpm 一样
url = "https://mirrors.aliyun.com/pypi/simple"
# 或者使用豆瓣源
url = "http://pypi.douban.com/simple"

# 依赖模块,类似 npm package.json 的 dependencies 字段
[packages]

# 开发环境下的依赖模块,类似 npm package.json 的 devDependencies 字段
[dev-packages]

# 运行需要的版本要求,类似 npm package.json 的 engine 字段
[requires]

# 还有其他的字段例如 [scripts],更多请参考官网 https://pipenv.pypa.io/en/latest/

初始化项目完成之后,我们来实战安装 flask 模块,来试试 pipenv 好不好用:

$ pip list # 先看下全局,有没有安装 flask 模块
$ pipenv install flask # 虚拟环境安装使用 pipenv install 而不再使用 pip install,而且默认安装到 [packages],如果想把模块安装到 dev-packages 下,需要加上 --dev,例如:pipenv install --dev module-name
$ pip list # 再看下全局,有没有安装 flask 模块,两次 pip list 只是为了确定没有把模块安装在全局。
$ ls # 查看目录会发现多出来一个 Pipfile.lock,这个文件和 npm 的 package-lock.json 文件功能是一样的,保证模块有效性。
Pipfile     Pipfile.lock
$ cat Pipfile # 查看  Pipfile 发现 packages 下增加了  flask 模块,`flask = "*"` 表示永远安装最新版的 flask
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
flask = "*"

[dev-packages]

[requires]
python_version = "3.9"

$ pipenv graph # 还可以查看安装模块依赖图
Flask==1.1.2
  - click [required: >=5.1, installed: 7.1.2]
  - itsdangerous [required: >=0.24, installed: 1.1.0]
  - Jinja2 [required: >=2.10.1, installed: 2.11.2]
    - MarkupSafe [required: >=0.23, installed: 1.1.1]
  - Werkzeug [required: >=0.15, installed: 1.0.1]

我们想执行虚拟环境里面的文件,有两种方式:

  • 进入虚拟环境执行:
$ pipenv shell # 可进入虚拟环境,成功进入命令行前面会有括号括起来项目的名字。
(myWeb-py) bash-5.0$ exit # exit 可以退出虚拟环境
  • 不进入虚拟环境执行
$ pipenv run pip list # pipenv run 可以不进入虚拟环境执行命令

一般都是不进入虚拟环境去执行文件,看到 pipenv run 你有没有想到 npm run,如果想到你一定还想到了 npm run 结合 scripts 的用法,没错 pipenv 也有这个功能,编辑 Pipfile 文件增加以下内容,我们新增了三个脚本:

[scripts]
start = "python main.py"
test = "pytest"
list = "pip list"

好了,我们编辑 main.py 使用 flask 来写个服务:

from flask import Flask
from flask import request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def print_hello(): # 视图函数
    # request.args 是个 ImmutableMultiDict
    # language 未定义时,给默认值 PyCharm
    # url 的 query 方法
    language = request.args.get('language', 'PyCharm')
    return f'Hello {language}!'

if __name__ == '__main__':
    app.run()

运行下这个文件:

$ pipenv run start
 * Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

这里有个WARNING⚠️,原因清楚明了,如果你不想看到它可以通过 pipenv shell FLASK_ENV=development FLASK_APP=main.py flask run 来运行代码。

打开浏览器,输入地址:http://127.0.0.1:5000/?language=World,你会看到:

Flask Hello World

好了,此时如果我想删掉安装的模块重新安装怎么办?类似 NodeJS 的 rm -rf node_modules && npm install 这个动作。

简单我们先删:

# Remove project virtualenv (inferred from current directory):
$ pipenv --rm
$ pipenv --venv # 查看虚拟环境是否还在,确定删除成功

然后我们重新安装模块:

# 重新安装的时候,如果本地没有对应的虚拟环境,会自动重新创建的。
$ pipenv install # 只安装 [packages] 下的模块
$ pipenv install --dev # 既安装 [packages] 下的模块,也安装 [dev-packages] 下的模块

如果还有老项目迁移的话,可以这么做:

pipenv install -r requirements.txt

好了,到此算是入门 pipenv 了。

其实项目中还有一个常用的 anaconda,不过它一般用来开发数据分析项目,因为里面内置了很多东西,不过平时后端开发并不常用:

Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。 [1] 因为包含了大量的科学包,Anaconda 的下载文件比较大(约 531 MB),如果只需要某些包,或者需要节省带宽或存储空间,也可以使用Miniconda这个较小的发行版(仅包含conda和 Python)。

总结

Python 和 NodeJS 很像,尤其是在模块管理方面,pip 和 npm 在使用上功能基本一致,但是应用到项目开发中,Python 本身的限制导致了不能像 NodeJS 那样简单有效的建一个项目。为了克服不同项目模块管理的问题,出现了 virtualenv(虚拟环境的说法),但是此时的模块管理依然不够方便,急需一个模块依赖文件。所以出现了大杀器 pipenv。

至此,pipenv 基本上完全实现了 npm 的功能,pipenv使 Python 的 pip 变得更加智能

Python 和 NodeJS 我想你精通任何一个,去学另一个语言都会很容易。

当前时间 Wednesday, January 13, 2021 01:59:45

补充

昨天写好并发布了,结果早上来上班一看,昨天写的东西全没了,哇咔咔……

你可能感兴趣的:(用 NodeJS 思想学 Python——搭建开发环境)