Python Package中的 __init__.py
Package 中 init 的历史
在一些 Python 相关的项目时,常常会看到 __init__.py文件,
当你使用某些编辑器创建 Python Package 的时候,它也会自动给你生成一个 __init__.py 文件。
这玩意到底是干什么用的?
这个 py文件 里是空的
看名字,像是用来做一些初始化操作的,实际情况呢,其实也差不多
其实在 Python3.2 版本之前,定义的 Package 下面一定要有 __init__.py 文件,
这样 Python 才知道它是一个 Package,才可以寻找到相关模块的路径从而被 import
而在 Python3.2 之后的版本,
就不需要再额外的去专门创建一个 __init__.py 来告诉 Python 它是一个 Package 了,
因为现在创建的包叫 Namespace package, Python 可以自动搜寻 Package 路径,
哪怕你的父包路径发生了改变,你在下次导入的时候, Python 还是会自动重新搜索包路径。
所以现在如果 package 中没有定义 __init__.py,依然可以导入使用
Package 中 init 的作用
区分模块
在Python 中,一个 py文件,对应的就是一个模块。
在 my_package包 中创建三个子包 package_one、package_two、package_three
我们在编写的python程序中,不能同时导入两个同名的模块,而我们的程序又要用到这两个 py文件 里的内容,那么可以采用将这两个 py文件 放入两个不同的包下,通过导入不同包的方式进行区分,导入这两个不同的模块。
在 package_one 的 my_moudel 文件中定义类test1
class test1():
print('*' * 10)
if __name__ == '__main__':
pass
在 package_two 的 my_moudel 文件中定义类test2
class test2():
print('*' * 20)
if __name__ == '__main__':
pass
在 package_three 的 my_moudel 文件中定义类test3
class test3():
print('*' * 30)
if __name__ == '__main__':
pass
新建一个 my_print.py 文件,导入3个 my_moudel 模块
import my_package.package_one.my_moudel
import my_package.package_two.my_moudel
import my_package.package_three.my_moudel
f1 = my_package.package_one.my_moudel.test1
f2 = my_package.package_two.my_moudel.test2
f3 = my_package.package_three.my_moudel.test3
# 运行 my_print.py文件,结果为:
**********
********************
******************************
绑定到当前的命名空间
分别在子包的 init 文件中写入以下内容:
package_one
print('这是子包 one 的 init')
package_two
print('这是子包 two 的 init')
package_three
print('这是子包 three 的 init')
在父亲包 my_package 中写入以下内容:
print('这是父亲包 的 init')
新建一个 test.py 文件(可建在my_package 包外面),进行导包操作
只导入父模块 my_package
import my_package
# 运行test.py文件,结果为:
# 这是父亲包 的 init
总结:只导入父模块的时候只会执行父模块中的 init
单独导入子模块 package_one
import my_package.package_one
# 运行test.py文件,结果为:
# 这是父亲包 的 init
# 这是子包 three 的 init
单独导入package_two
import my_package.package_two
# 运行test.py文件,结果为:
# 这是父亲包 的 init
# 这是子包 two 的 init
单独导入package_three
import my_package.package_three
# 运行test.py文件,结果为:
# 这是父亲包 的 init
# 这是子包 three 的 init
三个包均导入
import my_package.package_one
import my_package.package_two
import my_package.package_three
# 运行test.py文件,结果为:
# 这是父亲包 的 init
# 这是子包 one 的 init
# 这是子包 two 的 init
# 这是子包 three 的 init
总结:导入父模块中的子模块的时候,优先执行父模块中的 init ,再执行指定模块中的 init
也就是说,当我们去 import 一个 Package 的时候,它会隐性的去执行 __init__.py ,
而在 __init__.py 中定义的对象,会被绑定到当前的命名空间里面来。
有时候我们会这样去导入一个包下的所有模块:
from my_package import *
# 运行test.py文件,结果为:
# 这是父亲包 的 init
但这个时候却并没有将相关的子模块导入进来,如果想采用这种导包的方式,也将子模块导入进来,或者导入某些特定的子模块进来,可采用对 父亲包的 init 文件进行编辑:
print('这是父亲包 的 init')
__all__ = ['package_one','package_three']
# 这里的 __all__ 相当于导入 [] 里面定义的模块
此时再运行 test.py 文件
from my_package import *
# 运行test.py文件,结果为:
# 这是父亲包 的 init
# 这是子包 one 的 init
# 这是子包 three 的 init