以.py结尾的python文件,其中的成员可以包括“变量、函数、类 ”等等。
简单来说,包就是文件夹,但该文件夹下一般存在 __init__.py 文件(python3不严格要求,但强烈建议), 该文件的内容可以为空。__init__.py 用于标识当前文件夹是一个包,当一个包被import时,首先会自动加载它的__init__.py文件。
当你导入一个模块,Python 解析器对模块位置的搜索顺序是:
1、当前目录
2、如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
3、如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/pythonx.x/… ,anaconda安装一般为/xxx/anacondax/pythonx.x/lib/… 。
你可以通过sys.path变量看到上述所有路径(顺序也入上所诉),代码如下:。
# test.py
import sys
print(sys.path)
输出:(应该为整个长list,这边为了方便区分做了写修改。)
import语句用来载入模块,使用这种语法格式的 import 语句,会导入指定模块中的所有成员(包括变量、函数、类等)。当需要使用模块中的成员时,需用该模块名作为前缀,否则 Python 解释器会报错。
示例1:
其中PIL是包,Image是模块。Import 模块(Image)后,需要使用其中的函数(new)还是需要写上完整的前缀(PIL.Image.new)
示例2:
包(PIL)可也被直接import,但是如果只是导入一个包而不指名任何模块,且包中的__init__.py没有任何初始化操作,那么并不可以使用包内的模块及模块内的函数。
示例3:
import语句不能直接引用模块内的成员。
from … import … 可以从模块中引用它内部的成员(函数,变量等),此时可以不加模块的前缀直接使用。(建议使用某模块少量成员时使用此方法)
from … import … 可以从包中引用模块,此时可以直接使用”模块名.成员名“来调用模块内的所有成员。
示例1:
其中PIL.Image 是模块,new是模块内的函数,new可以不加模块前缀(Image)直接使用。
示例2:
其中PIL是包,Image是模块。引用后可以使用”模块名.成员名“来调用模块内的所有成员。
目录结构:
mypackage
├── __init__.py
├── module_bar.py
└── module_foo.py
从module_bar导入module_foo的几种方式:
# 方法一:
import module_foo
# 方法二:
# 如果是上层文件夹写.., 上上层文件夹写..., 以此类推
from . import module_foo
# 方法三:
from mypackage import module_foo
import mypackage.module_foo
其中:
对于python3而言,方法二是相对导入,方法一三是绝对导入。(python强烈不推荐相对导入)
目录:
.
└── mypackage
├── __init__.py
└── module_foo.py
模块module_foo.py内容:
import sys
print(sys.path)
直接运行:
python3 mypackage/module_foo.py
['/xxx/MyProject/mypackage', xxxx, xxx, xxxx]
可以看出,当搜索路径中的“1、当前目录”(见第一节)就是模块所以在的目录。
模块运行:
python3 -m mypackage.module_foo
['/xxx/MyProject', xxxx, xxx, xxxx]
可以看出,当搜索路径中的“1、当前目录”(见第一节)就是你的命令行所以在的目录。
目录:
src
├── bar_package
│ └── module_1.py
├── foo_package
│ ├── module_2.py
│ └── module_3.py
└── main.py
模块module_3.py的内容:
from bar_package import module_1
问题:
在foo_package下,使用python module_3.py 就会出现“ No module named 'bar_package' ”错误。
分析:
入上节所说,直接运行的方式会将要运行模块所在目录放入搜索路径(此例中就是foo_package目录)。这使得搜索路径对 bar_package包不可见,所以会产生错误。
(推荐)解决1:
使用模块运行的方法,在scr目录下运行:
python3 -m foo_package.module_3
入上节所说,此时scr目录被加入到搜索路径当中,搜索路径对 bar_package包可见。
(不推荐)解决2:
修改模块内容,添加相对搜索路径:
import sys
sys.path.append("../")
print(sys.path)
from bar_package import module_1
此时在foo_package下运行“python3 module_3.py”可以成功。输出如下:
['/xxx/src/foo_package', 'xxx', 'xxx', '../' ]
从打印中可以看出搜索路径sys.path在最后添加了'../',这使得它能够找到bar_package包。
但是,在src下运行“python3 foo_package/module_3.py”还是显示“ No module named 'bar_package' ”错误。
这是因为添加的搜索路径是一个相对路径(“../”),在src下运行时,"../"指的是src的上层路径,此时也无法搜索到bar_package包。
(推荐)解决3:
修改模块内容,添加绝对搜索路径:
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
print(sys.path)
from bar_package import module_1
此处用os.path.realpath(__file__)来获得文件所在的绝对路径。使用两个os.path.dirname()来代替相对路径中的“..”表示上层文件夹。
这时无论在何处使用直接运行方法运行module_3模块都能够正确地找到bar_package包。
Python中import的用法 - 知乎 (zhihu.com)
Python 模块 | 菜鸟教程 (runoob.com)
Python导入模块,Python import用法(超级详细) (biancheng.net)
[Python]解决python3中关于import的疑难杂症 - SegmentFault 思否