浅谈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的Django框架中的URL配置与松耦合
Jul 15 Python
分析Python中设计模式之Decorator装饰器模式的要点
Mar 02 Python
python 循环while和for in简单实例
Aug 16 Python
Python数据结构与算法之链表定义与用法实例详解【单链表、循环链表】
Sep 28 Python
pandas 根据列的值选取所有行的示例
Nov 07 Python
Python安装OpenCV的示例代码
Mar 05 Python
win10下opencv-python特定版本手动安装与pip自动安装教程
Mar 05 Python
Python Selenium截图功能实现代码
Apr 26 Python
PyTorch安装与基本使用详解
Aug 31 Python
通过实例了解python__slots__使用方法
Sep 14 Python
python 日志模块logging的使用场景及示例
Jan 04 Python
python中pyqtgraph知识点总结
Jan 26 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记录用户通过搜索引擎进网站的关键词
2014/02/13 PHP
利用PHP函数计算中英文字符串长度的方法
2014/11/11 PHP
PHP计算日期相差天数实例分析
2016/02/23 PHP
PHP如何根据文件头检测文件类型实例代码
2018/10/14 PHP
php微信公众号开发之音乐信息
2018/10/20 PHP
9行javascript代码获取QQ群成员具体实现
2013/10/16 Javascript
用jQuery模拟select下拉框的简单示例代码
2014/01/26 Javascript
基于javascript实现判断移动终端浏览器版本信息
2014/12/09 Javascript
使用VS开发 Node.js指南
2015/01/06 Javascript
jQuery显示和隐藏 常用的状态判断方法
2015/01/29 Javascript
js正则表达式replace替换变量方法
2016/05/21 Javascript
layui框架中layer父子页面交互的方法分析
2017/11/15 Javascript
详解webpack babel的配置
2018/01/09 Javascript
微信小程序实现登录遮罩效果
2018/11/01 Javascript
小程序实现授权登陆的解决方案
2018/12/02 Javascript
在node环境下parse Smarty模板的使用示例代码
2019/11/15 Javascript
Javascript实现html转pdf高清版(提高分辨率)
2020/02/19 Javascript
vue项目查看vue版本及cli版本的实现方式
2020/10/24 Javascript
[01:02]DOTA2上海特锦赛SHOWOPEN
2016/03/25 DOTA
Django框架的使用教程路由请求响应的方法
2018/07/03 Python
python中实现字符串翻转的方法
2018/07/11 Python
Python WSGI的深入理解
2018/08/01 Python
Python提取支付宝和微信支付二维码的示例代码
2019/02/15 Python
wxPython:python首选的GUI库实例分享
2019/10/05 Python
Python Lambda函数使用总结详解
2019/12/11 Python
Django2.1.7 查询数据返回json格式的实现
2020/12/29 Python
ellesse美国官方商店:意大利高级运动服品牌
2019/10/29 全球购物
英国在线定制百叶窗网站:Swift Direct Blinds
2020/02/25 全球购物
Windows和Linux动态库应用异同
2016/07/28 面试题
年度考核自我鉴定
2013/11/09 职场文书
安全检查与奖惩制度
2014/01/23 职场文书
争论的故事教学反思
2014/02/06 职场文书
娱乐节目策划方案
2014/06/10 职场文书
日语专业求职信
2014/07/04 职场文书
中学生勤俭节约倡议书
2015/04/29 职场文书
关于实现中国梦的心得体会
2016/01/05 职场文书