引言
一个称手的开发环境对于开发者的重要性是不言而喻的,在一个依赖版本不独立甚至经常发生版本冲突、代码编写缺乏必要提示的环境下,我们要长时间进行高效率的开发是相当困难的。在日常工作中,我们要做的除了代码编写外,还有协作开发、接口测试、文档编写等,在不同的环节中使用合适、高效的工具,往往会达到事半功倍的效果。
本篇文章会从 Linux 操作系统、Python 版本、包管理工具、虚拟环境、集成开发环境 IDE、常用开发辅助工具等几个方面出发,手把手帮助大家从零开始快速搭建高效的开发环境。
操作系统:为什么推荐大家使用 Linux 系统进行开发?
针对 Python 开发而言,在当下三大主流操作系统 Windows、Linux 以及 Mac OS 中,笔者优先推荐使用 Linux 系统进行开发:
- Linux 给予开发者更大的自由度,有助于开发者能力的提升。在 Linux 下可以通过众多的命令组合高效的进行问题定位。并且由于其开源特性,开发者对其操作系统层面的技术点认知可以更加深入;
- 目前大部分 Python 项目均会选择在 Linux 服务器上进行部署。要了解部署细节,参与部署系统及相关脚本的编写,或登录服务器进行问题调试等,都避免不了对 Linux 系统的熟练使用;
- 目前大部分公司会对 Python 工程师有掌握 Linux 的基本要求,往往还会在面试中对 Linux 系统中的相关技术点进行考核。
- …
Linux 快速开始
在这里笔者提供以下几种方法,帮助大家快速开始:
- 如果你已经开始使用 Linux 系统,不管是 centos、ubuntu、debian 等发行版中任何一个,那么恭喜你可以略过下面的内容;
- 如果你使用 Mac OS,由于 Mac OS 也是基于 Unix 的系统,大部分命令和 Linux 差别不大,所以一般情况下无需进行操作系统的切换,但还是需要了解 Linux 系统的常用技术点;
- 如果你已经在 Windows 下开发 Python 有一定经验,切换成本可能会相对大一些,你仍可继续使用当前的系统,想必后面的工具、库的安装对你来说也不算难事。;
- 如果你仅仅初学 Python 或者在 Windows 下掌握了一定 Python 基础,但还未长期开发项目,那么建议使用 Windows 结合虚拟机或者 Windows、Linux 双系统的方式。
我们在这里不再赘述 Linux 发行版之间的差别,为了兼顾大部分同学的开发和日常使用,在这里给出一个 Windows 结合虚拟机的解决方案供参考:Windows + VMware Workstation / VirtualBox + ubuntu,以下安装流程仅供大家参考:
-
VMware Workstation 虚拟机下载(选择 Windows 下的 VMware)以及安装(可下载免费试用版)。
-
ubuntu 下载,我们选择下载最新的长期支持版本 ubuntu 20.04 LTS(或者你也可以使用 ubuntu 18.04.3 LTS;若浏览器下载速度较慢,可以选择使用一些常用的下载软件进行下载)。
-
ubuntu 虚拟机创建可参考下图的流程:
-
创建成功后即为下图所示,可按照个人喜好进行设置,比如配置中文输入法、修改时区等(在遇到问题时,请合理使用官方文档与搜索引擎)。
Python 2 还是 Python 3:优先使用 Python 3.X 进行开发
ubuntu 20.04 自带了 Python 3.8.2 ,我们可以非常方便的进行使用,点击右键或使用快捷键 Ctrl + Alt + T
打开终端后键入 Python3 便可进入默认的 Python 交互式环境 。
对于选择 Python 2 还是 Python 3 开发,这其实已经是一个老生常谈的问题了。
从 2020 年 1 月起,Python 2 已处于 EOL( End Of Life )状态,不再获得进一步的官方支持,并且不会有进一步的更新或错误修复。至此,Python 2.X 的终止计划终于在花费了数十年的时间后得到了最终的完成(2020 年 4 月 20 日,Python 2.7.18 发布,这个具有特殊意义的版本为 Python 2 的时代画上了一个圆满的句号,在此感谢社区所有的贡献者为此所付出的一切)。
而且众多流行的第三方库也已经完成了 Python 2.X 向 Python 3.X 的迁移,同时对于 Python 开发者而言,大量新的、优秀的语言特性只能在 3.X 中使用,所以这里推荐大家在学习 Python 以及新项目的开发中优先使用 Python 3.X 。但与此同时,本课程还会对重要的 Python 2.X 中的技术点进行讲解,这是因为很多公司现存 Python 2.X 项目的数量并不少,你有可能在未来会碰到它们。关于 Python 2.X 和 Python 3.X 更详细的对比,可以参考本小节最后部分。
安装 Python 3.8.2 版本(供旧版本用户参考)
如果你并没有选择安装 ubuntu 20.04 LTS,而是 ubuntu 其他版本,那么通常这些版本中自带的 Python 相对落后一些,为了学习更多的新特性,我们在 ubuntu 中安装 Python 3.8.2:下载最新的python源码包并将该源码包放置在 /home/<用户名>
($HOME
) 目录下,如下图所示。
接下在我们需要在终端中进行命令行操作:
# 1.安装依赖包,防止源码编译失败(下面的命令在 ubuntu 终端中输入)
sudo apt-get -y install libncurses5-dev libbz2-dev libffi-dev libgdbm-dev liblzma-dev libsqlite3-dev libssl-dev libreadline6-dev gcc make zlibc zlib1g-dev
# 2.安装 python 3.8.2
mkdir tmp # tmp目录用于暂存解压文件,可在编译安装完成后删除
tar -xvf $HOME/Python-3.8.2.tar.xz -C tmp
cd $HOME/tmp/Python-3.8.2/
./configure
make
sudo make install
源码安装成功后,在终端中便可输入 python3.8 后进入交互环境,下面在交互环境中展示了部分 Python 官网的示例代码,接下来课程中的代码示例我们都会在该虚拟机上进行:
这里我们提供的方式是采用源码安装的方式,这种方式更加细节一些。除此之外的一种更加常用的方式是利用 pyenv 来安装不同的 Python 版本,并在多个版本之间进行切换。pyenv 常在生产环境中用来作为安装和管理 Python 版本的工具,支持安装包括 Python 2.X、Python 3.X、PyPy 等不同的 Python 版本。
Python 包管理工具 pip
什么是 pip?
pip 是 Python 的标准包管理工具,进行包管理用来安装、升级、卸载、查找、管理不属于 Python 标准库的其他第三方软件包。默认情况下 pip 将从 Python Package Index 查找及安装软件包。pip 从 Python 3 的 3.4 版本和 Python 2 的 2.7.9 版本开始就默认包含在 Python 二进制安装程序中。
pip的使用技巧
在安装好 Ubuntu 20.04 后我们需要安装 pip,执行 sudo apt install python3-pip
即可(如果你是手动执行的源码安装,则在我们安装好 Python 3.8.2 后,pip3 可直接使用)。安装完成后,我们在终端中键入 pip3 :
下面示例中的命令是一些在开发中与 pip 相关的常用命令。我们可以在终端中尝试运行(在终端中运行下面的命令时,若输出结果提示 Permission denied,可在命令前添加 sudo ):
# 安装最新版本的软件包
pip3 install requests
# 安装指定版本的软件包
pip3 install requests==2.21.0
# 升级到最新版本
pip3 install --upgrade requests
# 一次安装多个软件包,使用空格分开
pip3 install requests certifi chardet idna urllib3
# 卸载已安装的软件包,卸载多个软件包同上
pip3 uninstall requests
# 显示当前环境下安装的所有软件包
pip3 list
# 生成已安装软件包列表,常将此列表内容放在 requirements.txt 文件中
pip3 freeze > requirements.txt
# requirements.txt 文件中常用于版本控制,结合 install -r 可以一次性安装所有需要的软件包
pip3 install -r requirements.txt
使用虚拟环境工具隔离不同的 Python 环境
什么是 Python 虚拟环境(virtual environment)?
在 Python 官方文档中这样对虚拟环境进行解释:
一种采用协作式隔离的运行时环境,允许 Python 用户和应用程序在安装和升级 Python 分发包时不会干扰到同一系统上运行的其他 Python 应用程序的行为。
官方文档中的描述非常书面化,我们设想这样的场景帮助我们理解虚拟环境的概念,比如我们在当前的 ubuntu 系统中(假定该系统中目前只有一个全局安装的 Python 环境)运行着多个 Python 应用程序,如果多个 Python 应用程序使用了相同的第三方软件包,但不同的应用程序要求的版本不同,则会发生版本冲突,安装任一版本都会导致其他应用程序无法运行。解决这个问题的常用解决方案之一便是创建不同的虚拟环境,在每一个虚拟环境中都安装有特定的 Python 版本以及其他第三方软件包,不同的应用程序使用不同的虚拟环境即可。
当然,使用虚拟环境是有很多好处的,比如可以维护多个虚拟环境保证不同应用程序正常运行,可以保证全局的 Python 环境独立、可以更方便的管理不同应用程序的依赖关系。
Python 虚拟环境工具:virtualenvwrapper 和 pipenv
目前有多种可以用于创建和管理 Python 虚拟环境及版本的相关工具,诸如 venv / pyvenv 、virtualenv、 virtualenvwrapper、pyenv / pyenv-virtualenv、pipenv、Poetry 等,在这里要跟大家重点介绍的是 virtualenvwrapper 和 pipenv。
virtualenvwrapper
首先需要安装 virtualenvwrapper 并进行相关配置,方便我们后续使用:
# 安装 virtualenvwrapper(下面的命令在 ubuntu 终端中输入)
pip3 install virtualenvwrapper
# 定位 virtualenvwrapper.sh 的位置(用于下面的设置),
# 通常有两种常见的输出结果,分别为:/usr/local/bin/virtualenvwrapper.sh
# 或 /home/<用户名>/.local/bin/virtualenvwrapper.sh 等
sudo find / -name virtualenvwrapper.sh
# 修改 bashrc 文件
gedit ~/.bashrc # vi 或 vim 的话可以使用 vi ~/.bashrc
# 打开该文件后,在该文件最后添加如下代码,第一行代码用于设置虚拟环境的存放目录,第二行用于设置虚拟环境执行文件位置,添加代码后保存并退出
export WORKON_HOME=$HOME/.virtualenvs
# 下面两行内容中具体添加哪一个,取决于你的 virtualenvwrapper.sh 的具体位置,即我们上面 sudo find / -name virtualenvwrapper.sh 的输出结果
source $HOME/.local/bin/virtualenvwrapper.sh
# 或者
source /usr/local/bin/virtualenvwrapper.sh
# 执行被修改的初始化文件
source ~/.bashrc
# 若执行上述命令报错:virtualenvwrapper.sh: There was a problem running the initialization hooks,则需要对 virtualenvwrapper.sh 进行修改,定位到含有 which python 的行中,将 python 修改为 python3 后保存退出(也可以选择在 bashrc 中增加 export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3)
sudo gedit $HOME/.local/bin/virtualenvwrapper.sh
# 或者
sudo gedit /usr/local/bin/virtualenvwrapper.sh
# 重新执行被修改的初始化文件
source ~/.bashrc
上述命令运行成功后,我们便可以创建虚拟环境,在虚拟环境中我们便可以按需使用 pip 安装并管理软件包,并不会影响到虚拟环境外的其他 Python 环境。
# 我们可以自定义 mkvirtualenv 后面的虚拟环境名称,创建成功后会自动进入该虚拟环境,在目录的最右侧会自动添加上 (python-core-tech) 的前缀
mkvirtualenv python-core-tech
# 若执行上述命令时报错:ERROR: virtualenvwrapper could not find virtualenv in your path
gedit ~/.bashrc
# 在文件的最后添加下面的内容,保存并退出
export VIRTUALENVWRAPPER_VIRTUALENV=$HOME/.local/bin/virtualenv
source ~/.bashrc
在创建虚拟环境后,我们可以使用下面的命令对现有的虚拟环境进行管理:
# 进入或切换虚拟环境
workon <虚拟环境名称>
# 退出虚拟环境
deactivate
# 删除虚拟环境
rmvirtualenv <虚拟环境名称>
# 列出所有虚拟环境
lsvirtualenv
同样我们也可以在创建虚拟环境时指定已安装的 Python 版本:
# 指定 python3.6 创建名为 test 的虚拟环境(前提是你已安装了该版本的 Python 环境)
mkvirtualenv -p python3.6 test
# 若在执行上述命令时报错:ModuleNotFoundError: No module named 'distutils.spawn',则需要安装额外的软件包后重新执行上述命令
sudo apt-get install python3-distutils
由于我们在后面小节的一些语言特性的对比中也会使用到 Python 2.X ,所以我们在这里事先创建好对应的虚拟环境:
# 安装 Python 2.X
sudo apt install python2
# 创建名为 python-core-tech-2.7 的虚拟环境
mkvirtualenv -p python2.7 python-core-tech-2.7
环境迁移
当我们将某个开发环境内的应用程序部署到线上或迁移到其他虚拟环境内时,就需要进行环境的迁移,在新的环境下重新安装这个应用程序所有的依赖软件包。较为常用的一种方法是利用 requirements 文件,使用 pip freeze > requirements.txt
将开发环境下的所有依赖固化至该文件中,在新的环境中利用 pip install -r requirements.txt
安装依赖。
管理依赖的另外一种方式是结合 setuptools 在 setup.py
的 install_requires
中定义相关依赖库,这和 Python 项目的打包过程有关,关于这部分我们会在后面的小节中涉及。
pipenv
pipenv 的作者是著名的 Python 开发者 Kenneth Reitz,他同时也是 requests 库的作者。在众多的虚拟环境管理工具中,pipenv 的亮点在于:
-
同时包含 pip 包管理和虚拟环境工具两者的功能,使用更加的方便。
-
实现了 pip 包管理操作和软件包依赖记录的自动化处理,便于依赖管理和环境迁移。
使用 Pipfile 文件取代手动处理 requirements.txt 的方式,使用 Pipfile.lock 文件管理包的依赖关系,这两个文件都无需手动处理,会根据 pipenv 的相关命令自动进行变更。
-
在包管理过程中使用哈希校验,保证软件包的完整性。
不过,pipenv 目前仍然存在一些问题,建议大家持续关注,但如果要使用在生产环境上,请谨慎对待。另外,Poetry 同样也是一款值得关注的环境与依赖管理工具,在环境管理的基础上,还具有构建、打包、发布等功能。除此之外,在环境隔离方面,大家有兴趣还可以对 Anaconda / conda、docker 等工具进行了解。
集成开发环境 IDE
优秀的 IDE 有助于我们高效率的进行开发,在 Python 领域想必不用笔者赘述,都知晓 Pycharm 的大名。PyCharm 是 JetBrains 公司开发的一款 Python IDE,其支持语法高亮、代码调试、项目管理、代码提示、版本控制等基础功能,同时也具有众多额外的高级功能,比如对 Django、Flask 等常用框架的支持。
PyCharm 的安装
PyCharm下载 (选择 Linux 下专业版或者社区版)后同样将该压缩包放置在 ubuntu $HOME
目录下:
# 创建 software 目录
mkdir software
# 解压
tar -xvf $HOME/pycharm-professional-2020.1.1.tar.gz -C software/
# 启动 Pycharm
./software/pycharm-2020.1.1/bin/pycharm.sh
为了更加方便的使用,我们可以为 PyCharm 创建快捷方式:
关闭 PyCharm 后重新打开,右键点击桌面侧边栏的 PyCharm 图标 Add to Favorites,之后即可通过在左侧的菜单栏打开 PyCharm。
PyCharm 的配置
接下来我们利用我们之前建立的 python-core-tech 虚拟环境创建一个 Python 项目,打开 PyCharm 后选择 Create New Project,选择我们已经创建的虚拟环境。
创建项目后,我们在 PyCharm 左上角 File 中打开 Settings,可以调整主题、编辑器,设置快捷键,查看解释器环境,安装插件等。点击左下角 Python Console 便可进入交互式环境,后面的课程我们也会大量的使用该交互式环境。
PyCharm 常用使用技巧
我们先在项目中建立一个简单的 test.py
文件,下面的使用技巧大家可以在该文件中进行练习。
常用编码快捷键
打开 Settings,搜索 keymap,调整自己常用的快捷键组合方式,如果在下拉列表中没有找到自己常用的方式,可以在插件商店中下载安装,比如笔者安装了 Eclipse Keymap(对 Java 语言有过了解的话,一定对 Eclipse 不会陌生),建议大家使用 Eclipse 模式的快捷键组合方式。
下面则是一些常用的快捷键组合,比如删除当前行,注释、查找等。
快捷键组合 | 作用 |
---|---|
Ctrl + D | 删除当前行 |
Ctrl + Alt + L | 格式化代码 |
Alt + ↓ (↑) | 当前行和下一行(上一行)位置交换 |
Alt + ←(→) | 回到前一个(后一个)查看或编辑位置 |
Ctrl + / | 注释及取消注释选中行 |
Ctrl + L | 定位到该文件内某行某列 |
Ctrl + F | 该文件内查找、替换 |
Ctrl + H | 全局查找 |
Ctrl + 鼠标左键 | 跳入方法定义处 |
Ctrl + F6 | 不同窗口间切换 |
Ctrl + Tab | 代码块向前缩进 |
Ctrl + Shift + O | 组织 import 导入(调整 import 结构,去除无用导入) |
断点单步调试
如下图所示,我们鼠标左键单击第二行左侧至出现红点后,点击右上方红框中的 Debug 便可进入断点单步调试,使用快捷键 F6 单步跳过,使用 F8 结束调试继续运行。
如果在运行中遇到相关环境配置问题,大家可以在右上角 Configuration 中对 Script path 进行配置:
PyCharm 插件推荐
在 Pycharm 中已经自带了许多非常有用的插件,比如:
安装额外的插件可以在 Settings 中进入 Plugins,通过离线下载安装或在线安装,两种方式都非常方便。下面我们列举了几个常用的插件供大家参考:
插件名称 | 作用 |
---|---|
BashSupport | 对 bash 语法的支持,比如语法高亮、文档查看等 |
Rainbow Brackets | 对代码中多对括号进行区分 |
Key Promoter X | 快捷键提示 |
Material Theme UI | 更多酷炫的主题 |
CSV Plugin | 支持 CSV 等类型文件编辑 |
常用开发辅助工具推荐
在日常开发中,我们也可以借助一些常用的工具来提高效率,下面是一些常用的工具和对应的介绍:
工具名称 | 作用与特点 |
---|---|
Vim / Neovim | 代码编辑器,有效的进行服务器代码调试 |
Zsh / Oh My Zsh / fish | 命令行工具,提高命令行使用体验 |
tmux | 终端复用器 |
Terminator | 分屏工具,支持一个窗口中打开多个终端 |
Jupyter Notebooks | 可视化交互环境,兼顾代码、文档、可视化输出 |
FE 助手 | 谷歌 Chrome 前端插件,方便的处理转码、Json 数据等 |
Python 2.X 和 3.X
Python 2.X 到 3.X 的主要修改
Python 在每一个版本都发生着变化,在这里我们有必要对两个大版本进行简要的对比。如果对于其中的一些知识点比较模糊的话,不用担心,在后面的课程中会对这些技术点进一步阐述。
-
类:3.X 中所有类均为新式类,继承自
object
; -
Unicode 字符串:3.X 中
str
支持所有的 Unicode 文本,bytes
用于表示字节串,bytearray
作为可变的bytes
; -
可迭代对象:3.X 中
map
、filter
、zip
、range
、dict
的keys
/values
/items
等都是可迭代对象而不是一次性创建的列表; -
print
:3.X 中pirnt
是一个内置函数; -
整数与除法:3.X 中将
int
和long
统一为可以调整精度的int
类型;同时在 3.X 中,/
为真除法,会对结果保留小数; -
比较、排序:3.X 中不再支持混合类型间的、字典间的大小比较和排序。
# 下面的代码在 Python 2.X 下均能正常运行,但在 Python 3.X 下均会引发 TypeError >>> {1:2} > {3:4} Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: '>' not supported between instances of 'dict' and 'dict' >>> 1 > "2" Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: '>' not supported between instances of 'int' and 'str' >>> sorted([{1:2},{3:4}]) Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: '<' not supported between instances of 'dict' and 'dict' >>> sorted([1, "2"]) Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: '<' not supported between instances of 'str' and 'int'
-
相对导入:3.X 中相对导入不再支持隐式相对导入。
-
open
:3.X 中open
函数根据传入的参数在打开文件时对文本文件和二进制文件具有明确区分,文本文件的内容表示为str
,二进制文件的内容表示为bytes
。 -
推导:3.X 中推导(比如列表推导、字典推导等)中的临时变量作用域仅限于表达式内。
# Python 2.X >>> [i for i in [1,2,3]] [1, 2, 3] >>> i 3 # Python 3.X >>> [i for i in [1,2,3]] [1, 2, 3] >>> i Traceback (most recent call last): File "<input>", line 1, in <module> NameError: name 'i' is not defined
除以上主要的变化外,还有字节码存储方式、内置异常层次等在 3.X 中也发生了变化,同时 3.X 也移除了一部分功能,比如 raw_input
、xrange
、dict.has_key
等。
Python 3.X 的扩展与新增
除了上述我们提到的语言特性的修改和移除外,在 Python 3.X 中也新增了一些语言特性和基础库,下面我们按照不同的版本对一些新增的常用点进行简要的说明:
Python 3.0
- 函数注解( Function Annotations ),可以对函数的参数和返回值进行注解。除了可以通过
__annotations__
来访问这些注解外,没有其他更多的语义; - 仅限关键字形参( Keyword-only arguments ),在函数形参中使用
*
来表示对应的形参必须使用关键字进行传递; nonlocal
语句允许嵌套函数中的内部函数对外层函数作用域中的变量进行赋值;- 扩展的 Iterable 解包,比如
(a, *rest, b) = range(5);
; - 集合字面量,字典推导,新的八进制字面量,以
b
或B
开头的字节串等等;
Python 3.1
- 有序字典
collections.OrderedDict
; - 千位分隔符的格式说明符,比如
'{0:,d}'.format(1234567)
—>'1,234,567'
;
Python 3.2
- Argparse 命令行解析模块;
- 基于字典的日志配置
logging.config.dictConfig()
可以支持更灵活的配置方式; - concurrent.futures 模块 ;
- 将字节码文件单独存储在
__pycache__
目录;
Python 3.3
- 虚拟环境工具 venv 和 pyvenv,后者 pyvenv 在 Python 3.6 中已弃用;
- 隐式命名空间包;
- OS 和 IO 异常的层次结构优化;
- 委托给子生成器
yield from
; - 允许禁用链式异常上下文的显示从而获取更干净的错误消息,比如
raise AttributeError(attr) from None
;
Python 3.4
- pip 默认包含在 Python 的二进制安装程序中;
- 异步 I/O 库 asyncio;
- 支持枚举的模块 enum;
- 面向对象的文件系统路径模块 pathlib;
- 高级 I/O 复用模块 selectors;
- 用于数学统计的模块 statistics;
Python 3.5
- 使用 async 和 await 语法实现原生协程 ;
- 矩阵乘法运算符
a @ b
; - 类型标注支持的模块
typing
; - 进一步扩展带有
*
的可迭代对象解包操作和带有**
的字典解包操作;
Python 3.6
- 文字字符串插值,比如
f"He said his name is {name}."
; - 用于进一步增强类型标注的变量注释语法,比如
names: List[str] = []
; - 异步生成器,允许在
async
/await
中使用yield
; - 使用
async for
进行异步推导; - 用于生成高加密强度的随机数、密码、安全凭证的模块
secrets
;
Python 3.7
- 延迟的类型标注求值;
- 用于 Python 调试的内置
breakpoint()
函数; - 用于支持上下文变量的
contextvars
模块; - 声明数据类的
dataclass()
,比如:@dataclass class Person: name: str height: float weight: float = 130.0 p = Point('Bob', 175.5) print(p) # 输出 "Person(name=Bob, y=175.5, z=130.0)"
Python 3.8
- 赋值表达式语法
:=
; - 仅限位置形参( Positional-only parameters ),在函数形参中使用
/
来表示对应的形参必须使用位置进行传递。
总结
在本篇文章中,我们对 Linux 下 Python 开发环境的搭建进行了全方位的讲解和逐步的操作,涵盖的内容范围相对较广,包括操作系统、语言版本、包管理、虚拟环境、IDE 等多个方面,后续的课程中我们会持续在该环境下进行开发并继续丰富该开发环境中的各种功能。搭建适合自己的开发环境,还需要大家自己动手去体验各种工具,不断”折腾“,不断进步。
Tips:更多精品内容请点击这里。
共同学习,写下你的评论
评论加载中...
作者其他优质文章