浅谈Python __init__.py的作用


Posted in Python onOctober 28, 2020

我们经常在python的模块目录中会看到 "__init__.py"  这个文件,那么它到底有什么作用呢?

1. 标识该目录是一个python的模块包(module package)

如果你是使用python的相关IDE来进行开发,那么如果目录中存在该文件,该目录就会被识别为 module package 。

2. 简化模块导入操作

假设我们的模块包的目录结构如下:

.
└── mypackage
  ├── subpackage_1
  │  ├── test11.py
  │  └── test12.py
  ├── subpackage_2
  │  ├── test21.py
  │  └── test22.py
  └── subpackage_3
    ├── test31.py
    └── test32.py

如果我们使用最直接的导入方式,将整个文件拷贝到工程目录下,然后直接导入:

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 就很有作用了。我们先来看看该文件是如何工作的。

2.1 __init__.py 是怎么工作的?

实际上,如果目录中包含了 __init__.py 时,当用 import 导入该目录时,会执行 __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,如果执行了该文件就会输出:

print("You have imported mypackage")

下面直接用交互模式进行 import

>>> import mypackage
You have imported mypackage

很显然,__init__.py 在包被导入时会被执行。

2.2  控制模块导入

我们再做一个实验,在 mypackage/__init__.py 添加以下语句:

from subpackage_1 import test11

我们导入 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'

报错了。。。怎么回事?

原来,在我们执行import时,当前目录是不会变的(就算是执行子目录的文件),还是需要完整的包名。

from mypackage.subpackage_1 import test11

综上,我们可以在__init__.py 指定默认需要导入的模块

2.3  偷懒的导入方法

有时候我们在做导入时会偷懒,将包中的所有内容导入

from mypackage import *

这是怎么实现的呢? __all__ 变量就是干这个工作的。

__all__ 关联了一个模块列表,当执行 from xx import * 时,就会导入列表中的模块。我们将 __init__.py 修改为 。

__all__ = ['subpackage_1', 'subpackage_2']

这里没有包含 subpackage_3,是为了证明 __all__ 起作用了,而不是导入了所有子目录。

>>> from mypackage import *
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'subpackage_1', 'subpackage_2']
>>> 
>>> dir(subpackage_1)
['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']

子目录的中的模块没有导入!!!

该例子中的导入等价于

from mypackage import subpackage_1, subpackage_2

因此,导入操作会继续查找 subpackage_1 和 subpackage_2 中的 __init__.py 并执行。(但是此时不会执行 import *)

我们在 subpackage_1 下添加 __init__.py 文件:

__all__ = ['test11', 'test12']

# 默认只导入test11
from mypackage.subpackage_1 import test11

再来导入试试

>>> from mypackage import *
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'subpackage_1', 'subpackage_2']
>>> 
>>> dir(subpackage_1)
['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'test11']

如果想要导入子包的所有模块,则需要更精确指定。

>>> from mypackage.subpackage_1 import *
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'test11', 'test12']

3. 配置模块的初始化操作

在了解了 __init__.py 的工作原理后,应该能理解该文件就是一个正常的python代码文件。

因此可以将初始化代码放入该文件中。

到此这篇关于浅谈Python __init__.py的作用的文章就介绍到这了,更多相关Python __init__.py内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
简单介绍Python中用于求最小值的min()方法
May 15 Python
python实现的多线程端口扫描功能示例
Jan 21 Python
pandas.dataframe中根据条件获取元素所在的位置方法(索引)
Jun 07 Python
Python发送邮件功能示例【使用QQ邮箱】
Dec 04 Python
python在回调函数中获取返回值的方法
Feb 22 Python
利用Python实现手机短信监控通知的方法
Jul 22 Python
Python 写入训练日志文件并控制台输出解析
Aug 13 Python
numpy:np.newaxis 实现将行向量转换成列向量
Nov 30 Python
Tensorflow实现多GPU并行方式
Feb 03 Python
python3使用Pillow、tesseract-ocr与pytesseract模块的图片识别的方法
Feb 26 Python
python GUI模拟实现计算器
Jun 22 Python
详解解决jupyter不能使用pytorch的问题
Feb 18 Python
详解Selenium-webdriver绕开反爬虫机制的4种方法
Oct 28 #Python
详解Python流程控制语句
Oct 28 #Python
详解selenium + chromedriver 被反爬的解决方法
Oct 28 #Python
手把手教你从PyCharm安装到激活(最新激活码),亲测有效可激活至2089年
Nov 25 #Python
Python字典实现伪切片功能
Oct 28 #Python
python使用selenium爬虫知乎的方法示例
Oct 28 #Python
怎么解决pycharm license Acti的方法
Oct 28 #Python
You might like
php模板函数 正则实现代码
2012/10/15 PHP
php检测apache mod_rewrite模块是否安装的方法
2015/03/14 PHP
PHP-FPM之Chroot执行环境详解
2015/08/03 PHP
PHP如何通过AJAX方式实现登录功能
2015/11/23 PHP
PHP基于正则批量替换Img中src内容实现获取缩略图的功能示例
2017/06/07 PHP
PHP中类与对象功能、用法实例解读
2020/03/27 PHP
静态的动态续篇之来点XML
2006/12/23 Javascript
IE6/7 and IE8/9/10(IE7模式)依次隐藏具有absolute或relative的父元素和子元素后再显示父元素
2011/07/31 Javascript
JavaScript利用构造函数和原型的方式模拟C#类的功能
2014/03/06 Javascript
node.js正则表达式获取网页中所有链接的代码实例
2014/06/03 Javascript
JavaScript实现按照指定长度为数字前面补零输出的方法
2015/03/19 Javascript
javascript实现回到顶部特效
2015/05/06 Javascript
使用EVAL处理jqchart jquery 折线图返回数据无效的解决办法
2015/11/26 Javascript
跨域请求的完美解决方法(JSONP, CORS)
2016/06/12 Javascript
jQuery实现ajax的叠加和停止(终止ajax请求)
2016/08/08 Javascript
Nodejs中Express 常用中间件 body-parser 实现解析
2017/05/22 NodeJs
基于JS脚本语言的基础语法详解
2017/07/22 Javascript
select获取下拉框的值 下拉框默认选中方法
2018/02/28 Javascript
layui的table中显示图片方法
2018/08/17 Javascript
微信小程序webview 脚手架使用详解
2019/07/22 Javascript
小程序实现简单语音聊天的示例代码
2020/07/24 Javascript
原生js 实现表单验证功能
2021/02/08 Javascript
[05:08]2014DOTA2国际邀请赛 Hao专访复仇的胜利很爽
2014/07/15 DOTA
[01:03]悬念揭晓 11月26日DOTA2完美盛典不见不散
2017/11/23 DOTA
python中pycurl库的用法实例
2014/09/30 Python
python轻松实现代码编码格式转换
2015/03/26 Python
Python3.2中Print函数用法实例详解
2015/05/19 Python
Pycharm设置utf-8自动显示方法
2019/01/17 Python
橄榄树药房:OLIVEDA
2019/09/01 全球购物
简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程
2012/04/17 面试题
毕业生简历自我评价范文
2014/04/09 职场文书
团代会开幕词
2015/01/28 职场文书
投资意向协议书
2015/01/29 职场文书
商务英语求职信范文
2015/03/19 职场文书
golang 生成对应的数据表struct定义操作
2021/04/28 Golang
Django一小时写出账号密码管理系统
2021/04/29 Python