__init__.py
的作用
本文转自:https://www.cnblogs.com/tp1226/p/8453854.html
有稍许修改和个人理解。
1 标识该目录是python的包(module package)
- 如果在代码中
import
一个目录,则该目录必须是一个包。 - 如果使用python相关的IDE进行开发,如果目录中存在该文件,该目录会被识别为module package。
2 简化模块的导入操作
假设我们的模块包的目录结构如下:
.
└── mypackage
├── subpackage_1
│ ├── test11.py
│ └── test12.py
├── subpackage_2
│ ├── test21.py
│ └── test22.py
└── subpackage_3
├── test31.py
└── test32.py
第一行的.
表示当前工作目录,我们所有需要import mypackage
的文件都在这个目录下,下文所涉及到的所有命令界面也都是这个工作目录。
我们可以选择直接的导入方式,将整个文件拷贝到工程目录下,然后直接导入:
from mypackage.subpackage_1 import test11
from mypackage.subpackage_1 import test12
from mypackage.subpackage_2 import test21
from mypackage.subpackage_2 import test22
from mypackage.subpackage_3 import test31
from mypackage.subpackage_3 import test32
当然这个例子里面的文件比较少,如果模块比较大,目录比较深的话,可能自己都记不清该如何导入。(很有可能,哪怕只想导入一个模块都要在目录中找很久)
这种情况下,__init__.py
就派上用场了。下面我们来看看它是如何工作的。
3 __init__.py
的工作方式
在mypackage
文件夹下增加一个__init__.py
文件,然后import mypackage
的话,会自动执行__init__.py里面的代码。
下面是一个实验,先在mypackage
下新建一个__init__.py
:
.
└── mypackage
├── __init__.py
├── subpackage_1
│ ├── test11.py
│ └── test12.py
├── subpackage_2
│ ├── test21.py
│ └── test22.py
└── subpackage_3
├── test31.py
└── test32.py
./mypackage/__init__.py
里面的代码如下:
print("You have imported mypackage")
下面直接在交互模式下import mypackage
:
>>> import mypackage
You have imported mypackage
可以看出,__init__.py
被执行。
4 __init__.py
控制模块导入
再做一个实验,我们导入mypackage
下的subpackage_1/test11
,由于subpackage
和__init__.py
在同一文件夹下,按惯性思维,我们应该在__init__.py
中添加以下语句:
from subpackage_1 import test11
我们import mypackage
试一试:
>>> import mypackage
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/taopeng/Workspace/Test/mypackage/__init__.py", line 2, in <module>
from subpackage_1 import test11
ImportError: No module named 'subpackage_1'
报错了我,提示没有subpackage_1
模块,这是为什么?
原来,我们在import mypackage
时的工作目录是.
,不是__init__.py
所在的目录,而import
是按工作目录寻找模块的,所以__init__.py
中import
时应该按照工作目录,故将上一句改为:
from mypackage.subpackage_1 import test11
综上,我们可以利用__init__.py
文件指定import mypackage
时要导入的模块。
5 __all__
的用法
上面讲的都是import mypackage
的用法。我们知道在导入时可以直接导入包里面的所有内容,即用下面这行代码代替import mypackage
:
from mypackage import *
这时就需要__all__
这个特殊变量了。
__all__
关联了一个存储了模块名称的列表,当执行from xx import *
时,就会自动导入列表中的模块。
实验1 :
我们将__init__.py
修改为:
__all__ = ['subpackage_1', 'subpackage_2'] # 没有包含subpackage_3,是为了证明__all__起了作用,而不是导入了所有mypackage的子目录
然后再在交互界面执行:
>>> from mypackage import *
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'subpackage_1', 'subpackage_2']
>>> dir(subpackage_1)
['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
>>> dir(subpackage_2)
['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
可以看到subpackage_3
没有被导入。但是subpackage_1
和subpackage_2
中的模块也没有被导入!
那么上述导入就相当于执行了:
from mypackage import subpackage_1, subpackage_2
所以导入操作会继续查找subpackage_1
和subpackage_2
中的__init__.py
文件并执行(而不是执行import *
)。
实验2 :
我们在subpackage_1
中新建__init__.py
文件:
.
└── mypackage
├── __init__.py
├── subpackage_1
│ ├── __init__.py
│ ├── test11.py
│ └── test12.py
├── subpackage_2
│ ├── test21.py
│ └── test22.py
└── subpackage_3
├── test31.py
└── test32.py
在mypackage/subpackage/__init__.py
中添加一下代码:
__all__ = ['test11', 'test12']
# 默认情况下只导入test11
from mypacakge.subpackage_1 import test11
再来导入试试:
>>> from mypackage import *
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'subpackage_1', 'subpackage_2']
>>> dir(subpackage_1)
['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'test11']
>>> dir(subpackage_2)
['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
如果想要将test11
和test12
都导入,则需要更精确的指定:
>>> from mypackage.subpackage_1 import *
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'test11', 'test12']