Python: 进阶系列之四:项目的实战技巧

1. 使用requirement一次性安装项目需要的所有模块

1. 对于新项目,新建文件requirements.txt


PS C:\CongStudy\python-study> cat requirements.txt
python-dotenv
pipreqs
requests==2.18.4

# 通过如下命令可以一次性将如上三个包给安装上
PS C:\CongStudy\python-study> pip install -r requirements.txt

2. 将项目要部署到新环境,则需要在新环境中安装需引入的模块

第一步,安装pipreqs,运行命令

pip install pipreqs

第二步,运行如下命令,生成requirements.txt, 这里面会包含项目中所有引入的模块

pipreqs ./

第三步,运行命令,将requirements.txt中所有的模块安装上, -r 就表示使用requirement的方式来安装

pip install -r requirements.txt

2. 设置配置文件

通常在实际项目中,我们不能将数据库连接字符串、用户名、密码等信息直接写入代码中,我们一般会将它写入配置文件,而且不同运行环境所需要的配置信息也各不相同,比如:在开发环境和生产环境所使用的数据库连接字符串就不一样。下面将介绍如何使用创建并使用配置文件。

1. 安装模块 python-dotenv

pip install python-dotenv

2. 创建文件 .env,它就是配置文件,可以写入多个键值对,  这里只写了一个:USERNAME= congcong

3. 如何使用配置文件,代码如下:

from dotenv import load_dotenv
import os

# 运行如下命令,才能将 .env里的信息引进来
load_dotenv()


MY_NAME = os.getenv('MYNAME')
my_name = os.getenv('myname')

print(MY_NAME)
print(my_name) # 可见.env里的键值对中,键的大小写不敏感


# =============输出如下======================
# congcong
# congcong

4.  通常来说,实现上述三个步骤就够了,使用git签入代码时,不应该签入.env文件,因为.env里可能包含密码等敏感信息,如果我们使用云平台或DevOps来部署我们的应用程序的话,应该将此配置信息写在云平台或者DevOps的配置里。但有时候我们想在本地测试多个环境,可以使用多个.env配置文件, 假设我们有3个环境:local, stage, prod,分别三个不同的文件:.env, stage.env, prod.env, 这三个文件的内容如下:


# .env 
myname= this is the name from local

# stage.env
myname= this is the name from stage

# prod.env
myname= this is the name from prod

接着我们创建一个新的python文件,second-demo.py, 并写入如下代码: 

from dotenv import load_dotenv,find_dotenv
import os
ENV='stage'

if ENV =='stage':
    envfile = os.path.join('.','stage.env')
elif ENV =='prod':
    envfile= os.path.join('./prod.env')
else:
    envfile = os.path.join(find_dotenv())

load_dotenv(envfile)

print(os.getenv('myname'))  

 可以看到,当设置ENV = 'stage', 程序会读取stage.env配置文件, 设置ENV = 'prod',程序会读取prod.env配置文件,默认会读取.env配置文件。显示结果如下:

3. 设置虚拟环境

在实际开发中,通常我们不使用gobal的python环境,这对我们想使用不同版本的python环境时非常有用,我们会为每个项目创建单独环境,这里用到了虚拟环境,下面将介绍如何创建虚拟环境

1. 创建虚拟环境,运行如下命令,-m 表示将venv模块当作脚本去运行,最后一个venv表示文件夹名,创建虚拟环境实际上只在你的项目中创建了这个文件夹,它并不会重新创建整套python运行环境

python -m venv venv

安装完成后,可以看到.vscode/settings.json中多了一行:

 "python.pythonPath": "venv\\Scripts\\python.exe"

 它实际就是告诉当前项目运行的interpreter(python解释器)的路径。

2. 如果你是使用pycharm,在你创建项目时,已经帮你创建好了虚拟环境,你不必关心它, 如果你是使用VSCode的话,在终端窗口运行python命令,它默认的还是gobal的python环境,不是你当前的创建好的虚拟环境,如果想在当前的虚拟环境中运行程序,你有两个选择可以做:

(1)关闭terminal,重新打开一个新的terminal,它默认执行一段脚本将python解释器的路径指向当前虚拟环境。

(2)在当前terminal,执行如下命令,执行完成之后,你会在命令行的前面看到有(venv)的前缀,这时就说明当前的虚拟环境准备就绪了,如下 。

# window 环境下运行的命令
./venv/Scripts/activate.ps1

4.  解决ModuleNotFoundError: No module named 'XXX'的问题

通常在实际项目中会包含许多包,包里面的不同模块之间、不同包之间都会互相调用,会引发ModuleNotFoundError的错误 。在讨论几种异常情况前,先说明一下if __name__=="__main__": 的用法,它是用于执行当前python文件,这对我们测试本文件的时候非常有用。从如下4张图可以看出:

  • A.py 和B.py都是包module_demo里面
  • A.py写了一个方法
  • b.py 调用了A.py的方法
  • AA.py 调用了module_demo包里A.py 和B.py里面的两个方法

下面来讨论一下几种情况:

  1. 直接运行AA.py, 调用A.py里的方法,它是可以正确打印出字符串A
  2. 直接运行AA.py,调用B.py里的方法,B.py会调用A.py,它也是可以正确打印出字符串A,注意这里,B.py中的第一行代码,它不是直接import A, 意思就是说当B.py会调用A.py时,基于AA.py的当前路径去找A.py, 所以我们在B.py中的第一行代码中必须写成from module_demo import A
  3. 直接运行B.py,因为我们想单独测试B中的代码是否好用。这时它会报 ModuleNotFoundError: No module named 'module_demo',原因是由于直接运行B.py时,B.py就是最顶层的执行模块,它是不会再向上找module_demo包的。

那么问题来了,如果我既希望项目能从根目录进行,也希望每个文件可以单独测试,那该怎么处理呢 ,有以下解决办法:

(1)如果是使用pycharm编辑器,一般情况下,它已经帮你处理的了这些包之间的问题,如果有问题,请右击项目根目录将目录标记为根源,使py查找你要导入的模块时从此处开始查找。

(2) 如果你是使用命令行工具,那需要在B.py写入如下代码,因为python解释器就是通过sys.path去寻找模块的,但这种方法属于一次性的,只对当前的python解释器进程有效,关掉python重启后此路径就失效了。

import sys 
sys.path.append(’引用模块的地址’)

(3) 直接修改环境变量:在windows中是 “ set 变量=‘路径’  ” 例如:set PYTHONPATH=‘C:\test\...’,查看是否设置成功用echo %PYTHONPATH%,而且进到python解释器中查看sys.path,会发现已经有了新增加的路径了。这 种方式是永久的,一次设置以后一直都有效。在linux中是 "export 变量=‘路径’ “,查看是" echo $变量 "。

(4)如果你使用得是vscode,并且设置的虚拟环境,在window环境下,./venv/Scripts/activate.ps1的最后一行加上:


set-item env:pythonpath <您的项目的根路径>

# 例如 set-item env:pythonpath "C:\CongProjects\qihuoscrapy"

这样,当您每次在虚拟环境中运行的时候,无论运行任何一个python文件,它都会自动地从根目录去寻找包。 

小结:如果用不pycharm的话,上述方案(2)和(3)看上去都不那么友好。因为我不想在每一个python里加额外的代码,也不想修改我机器的环境变量。方案(4)正好是本人需要的答案。

发布了105 篇原创文章 · 获赞 46 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/wucong60/article/details/101845789