浅谈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 相关文章推荐
python3模拟百度登录并实现百度贴吧签到示例分享(百度贴吧自动签到)
Feb 24 Python
Python 异常处理实例详解
Mar 12 Python
Windows系统下安装Python的SSH模块教程
Feb 05 Python
Python基于PycURL实现POST的方法
Jul 25 Python
Saltstack快速入门简单汇总
Mar 01 Python
Python实现的堆排序算法示例
Apr 29 Python
浅析python参数的知识点
Dec 10 Python
解析Python的缩进规则的使用
Jan 16 Python
python实现词法分析器
Jan 31 Python
python psutil监控进程实例
Dec 17 Python
Python urllib.request对象案例解析
May 11 Python
Python轻量级web框架bottle使用方法解析
Jun 13 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封装的数据库保存session功能类
2016/07/11 PHP
PHP简单获取随机数的常用方法小结
2017/06/07 PHP
Laravel 创建指定表 migrate的例子
2019/10/09 PHP
Mozilla 表达式 __noSuchMethod__
2009/04/05 Javascript
Javascript load Page,load css,load js实现代码
2010/03/31 Javascript
js解析与序列化json数据(一)json.stringify()的基本用法
2013/02/01 Javascript
animate动画示例(泪奔的小孩)及stop和delay的使用
2013/05/06 Javascript
在Iframe中获取父窗口中表单的值(示例代码)
2013/11/22 Javascript
js弹出div并显示遮罩层
2014/02/12 Javascript
jquery 根据name名获取元素的value值
2015/02/27 Javascript
JavaScript使用forEach()与jQuery使用each遍历数组时return false 的区别
2016/08/26 Javascript
详解基于webpack搭建react运行环境
2017/06/01 Javascript
vue.js与element-ui实现菜单树形结构的解决方法
2018/04/21 Javascript
JS函数内部属性之arguments和this实例解析
2018/10/07 Javascript
详解react native页面间传递数据的几种方式
2018/11/07 Javascript
Vue 动态组件与 v-once 指令的实现
2019/02/12 Javascript
[01:02]2014 DOTA2国际邀请赛中国区预选赛 现场抢先看
2014/05/22 DOTA
[04:54]DOTA2 2017国际邀请赛:上届冠军WINGS采访短片
2017/08/09 DOTA
[59:36]2018DOTA2亚洲邀请赛 4.3 突围赛 Secret vs VG 第二场
2018/04/04 DOTA
Python heapq使用详解及实例代码
2017/01/25 Python
python探索之BaseHTTPServer-实现Web服务器介绍
2017/10/28 Python
详谈Python 窗体(tkinter)表格数据(Treeview)
2018/10/11 Python
对Python3中bytes和HexStr之间的转换详解
2018/12/04 Python
Python3实现的旋转矩阵图像算法示例
2019/04/03 Python
Pycharm运行加载文本出现错误的解决方法
2019/06/27 Python
python用for循环求和的方法总结
2019/07/08 Python
django框架模型层功能、组成与用法分析
2019/07/30 Python
Python实现鼠标自动在屏幕上随机移动功能
2020/03/14 Python
如何用Python绘制3D柱形图
2020/09/16 Python
CSS3属性background-size使用指南
2014/12/09 HTML / CSS
很酷的HTML5电子书翻页动画特效
2016/02/25 HTML / CSS
打架检讨书100字
2014/01/19 职场文书
《李广射虎》教学反思
2014/04/27 职场文书
办公室主任岗位承诺书
2014/05/29 职场文书
竞选学委演讲稿
2014/09/13 职场文书
《地震中的父与子》教学反思
2016/02/16 职场文书