引言
为什么我们import os, improt sys, improt math
等模块,就可以成功导入其模块,而随便import aaa
,就不行呢。那是因为Python
的导包路径原因,让我们来康康Python
的导包路径,是怎样的机制。
<br/>
查看导包路径
可以通过内置sys
模块来查看导包路径。
In [1]: import sys
In [2]: sys.path
Out[2]:
['D:\\Hui\\DevelopEnv\\Python\\Python379\\Scripts\\ipython.exe',
'd:\\hui\\developenv\\python\\python379\\python37.zip',
'd:\\hui\\developenv\\python\\python379\\DLLs',
'd:\\hui\\developenv\\python\\python379\\lib',
'd:\\hui\\developenv\\python\\python379',
'',
'd:\\hui\\developenv\\python\\python379\\lib\\site-packages',
'd:\\hui\\developenv\\python\\python379\\lib\\site-packages\\IPython\\extensions',
'C:\\Users\\Administrator\\.ipython']
In [3]:
<br/>
sys.path
返回的是一个路径列表,其代表Python导包时搜素的路径。
- Python解释器从
sys.path
里依次查找要导入的模块文件或包 ''
表示当前路径sys.path
列表中的路径的先后顺序代表了Python解释器在搜索模块时的先后顺序
<br/>
内置模块、包存放路径
像os, sys, json
等一些内置模块、包都存放在你下载 Python解释器时,其保存路径的Lib
目录
<br/>
存放路径以我个人的举例:
D:\Hui\DevelopEnv\Python\Python379\Lib
<br/>
<br/>
<br/>
下载的第三方库存放路径
像requests
、ipython
这些自己下载的第三方库等都存放在Lib
下的site-packages
目录下
<br/>
存放路径以我个人举例
D:\Hui\DevelopEnv\Python\Python379\Lib\site-packages
<br/>
<br/>
然而导包路径sys.path
就包含这两个路径
<br/>
因此我们使用import os
、import sys
、import json
、import requests
等都可以找到相应的模块和包
<br/>
如果导入模块和包时在sys.path
中没有搜索到相对应的模块,则会报如下错误
ModuleNotFoundError: No module named 'xxx'
<br/>
import aaa
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
<ipython-input-4-37ad1770aa41> in <module>
----> 1 import aaa
ModuleNotFoundError: No module named 'aaa'
其原理跟我们的电脑的环境变量-Path有点像。
我们可以在cmd
窗口输入python
可以打开python 交互解释器
,pip install xxx
可以下载第三方库。都是因为系统环境变量-Path,有具体可执行文件的路径
<br/>
<br/>
<br/>
追加新的导包路径
我们可以在程序运行时动态追加新的导包路径,代码如下
sys.path.append('D:\Hui\Code\Python\demo') # 追加到末尾
sys.path.insert(0, 'D:\Hui\Code\Python\demo') # 追加到开头位置,可以确保先搜索这个路径
<br/>
ipython 测验
<br/>
<br/>
现在D:\Hui\Code\Python\demo
目录下有一个aaa.py
模块。
<br/>
aaa.py
模块内容如下
# aaa.py
def test():
print('追加导包路径成功')
导包路径没追加D:\Hui\Code\Python\demo
时,import aaa
会报错
追加之后,在试试
<br/>
追加导包路径之后就可以成功导入并使用了。
<br/>
Django项目追加导包路径
来康康导包路径的具体应用场景。
在Django
中我们通常把子应用模块统一放在apps
包下,但在注册子应用的时候,该如何设置路径呢?
<br/>
我们在配置文件settings.py
ordevelop.py
中添加打印导包路径的代码
import sys
from pprint import pprint
pprint(sys.path)
其中pprint
是pretty print
美化输出的意思,这样输出的列表不会在一行上。
然后运行Django
程序查看导包路径结果
['C:\\Users\\Administrator\\Desktop\\meiduo_project\\meiduo_mall',
'C:\\Users\\Administrator\\Desktop\\meiduo_project',
'D:\\Hui\\DevelopTools\\PyCharm '
'2020.2.3\\plugins\\python\\helpers\\pycharm_display',
'd:\\hui\\developenv\\python\\python379\\python37.zip',
'd:\\hui\\developenv\\python\\python379\\DLLs',
'd:\\hui\\developenv\\python\\python379\\lib',
'd:\\hui\\developenv\\python\\python379',
'D:\\Hui\\VirtualEnv\\meiduo_mall',
'D:\\Hui\\VirtualEnv\\meiduo_mall\\lib\\site-packages',
'D:\\Hui\\DevelopTools\\PyCharm '
'2020.2.3\\plugins\\python\\helpers\\pycharm_matplotlib_backend']
已知导包路径
meiduo_project/meiduo_mall
已知users
应用所在目录
meiduo_project/meiduo_mall/meiduo_mall/apps/users
因此导入users
应用的路径可以写为:meiduo_mall/apps/users
知道导包路径我们就好在配置文件settings.py
ordevelop.py
中注册子应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'meiduo_mall.apps.users', # 注册用户模块
]
<br/>
是否可以将注册users
应用做的更加简便?按照如下形式,直接以应用名users
注册
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users', # 注册用户模块
]
<br/>
分析:
已知导包路径
meiduo_project/meiduo_mall
已知
users
应用所在目录meiduo_project/meiduo_mall/meiduo_mall/apps/users
若要直接以应用名
users
注册- 需要一个导包路径:
meiduo_project/meiduo_mall/meiduo_mall/apps
- 需要一个导包路径:
解决办法
- 追加导包路径:
meiduo_project/meiduo_mall/meiduo_mall/apps
<br/>
在配置文件settings.py
ordevelop.py
中追加导包路径
sys.path.insert(0, r'meiduo_project/meiduo_mall/meiduo_mall/apps/users')
<br/>
在项目中一般不会写死路径,因此利用BASE_DIR
来动态拼接路径
打印BASE_DIR
内容如下
'C:\\Users\\Administrator\\Desktop\\meiduo_project\\meiduo_mall\\meiduo_mall'
其路径怎么得来的呢,我们来分析一下代码
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- 其中
__file__
是指向当前模块 os.path.abspath(__file__)
是获取当前模块的绝对路径os.path.dirname(os.path.abspath(__file__))
则是根据当前模块路径获取其所在目录
因此:
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
就是获取当前模块的所在目录的上一层目录。
<br/>
我这里的当前模块是develop.py
,所在目录为settings
,settings
的上一层目录则是meiduo_mall
因此我们可以通过BASE_DIR
动态拼接路径,来添加导包路径
# 追加子应用导包路径
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
注册子应用直接写应用名就可以了。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 'meiduo_mall.apps.users'
'users'
]
<br/>
导包路径的作用
通过查看导包路径,可以快速的知道项目中各个包该如何的导入。接手项目时,可以尽快的适应项目导包的方式。
通过追加导包路径,可以简化某些目录复杂的导包方式。
<br/>
重新导入模块
模块被导入后,import module
不能重新导入模块,重新导入需用imp
下的reload
from imp import reload
<br/>
我们还是已上文提到的aaa.py
模块举例
# aaa.py
def test():
print('追加导包路径成功')
<br/>
ipython 测验
In [21]: import aaa
In [22]: aaa.test()
追加导包路径成功
In [23]:
这时不要关掉ipython
然后修改aaa.py
模块的如下
# aaa.py
def test():
print('重新导入模块测试')
<br/>
然后回到ipython
中测验
# 没修改前
In [21]: import aaa
In [22]: aaa.test()
追加导包路径成功
# 修改之后
In [23]: aaa.test()
追加导包路径成功
In [24]: import aaa
In [25]: aaa.test()
追加导包路径成功
In [26]:
其实aaa.py
已经修改了,只是当前ipython
交互器不知道,我们可以再开一个ipython
交互器验证一下
In [3]: import sys
# 我的aaa.py 模块不在当前导包路径下,因此要动态追加一下
In [4]: sys.path.insert(0, 'D:\Hui\Code\Python\demo')
In [5]: import aaa
In [6]: aaa.test()
重新导入模块测试
In [7]:
<br/>
因此aaa
模块被导入后,import aaa
不能重新导入模块,重新导入需使用如下方式
# 没修改前
In [21]: import aaa
In [22]: aaa.test()
追加导包路径成功
# 修改之后
In [23]: aaa.test()
追加导包路径成功
In [24]: import aaa
In [25]: aaa.test()
追加导包路径成功
In [27]: from imp import reload
In [28]: reload(aaa)
Out[28]: <module 'aaa' from 'D:\\Hui\\Code\\Python\\demo\\aaa.py'>
In [29]: aaa.test()
重新导入模块测试
<br/>
✍ 码字不易,万水千山总是情,点赞再走行不行,还望各位大侠多多支持❤️
<br/>
公众号
新建文件夹X
大自然用数百亿年创造出我们现实世界,而程序员用几百年创造出一个完全不同的虚拟世界。我们用键盘敲出一砖一瓦,用大脑构建一切。人们把1000视为权威,我们反其道行之,捍卫1024的地位。我们不是键盘侠,我们只是平凡世界中不凡的缔造者 。