浅谈Python __init__.py的作用

我们经常在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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python基础之包的导入和__init__.py的介绍

    调用同级目录: – src |– mod.py |– test.py 若在程序test.py中导入模块mod, 则直接使用 import mod 或 from mod import * 调用子目录下的模块: – src |– mod.py |– lib | |– mod2.py |– test.py from lib.mod2 import * 或 import lib.mod2 调用上级目录下的文件 目录结构如下: – src |– mod.py |– lib | |– mod2.py |–

  • Python模块包中__init__.py文件功能分析

    本文实例讲述了Python模块包中__init__.py文件功能.分享给大家供大家参考,具体如下: 用django做开发已经一年多的时间,但基本没注意python模块中__init__.py文件存在的意义,偶然看到对它的介绍吓一大跳,这个文件太重要了 模块包: 包通常总是一个目录,目录下为首的一个文件便是 __init__.py.然后是一些模块文件和子目录,假如子目录中也有 __init__.py 那么它就是这个包的子包了. 差不多就像这样吧: Package1/ __init__.py   

  • Python包,__init__.py功能与用法分析

    本文实例讲述了Python包,__init__.py功能与用法.分享给大家供大家参考,具体如下: 包: 为了组织好模块,将多个模块组合为一个包,所以包用于存放python模块 包通常是一个文件夹,当文件夹当作包使用时,文件夹需要包含__init__.py文件 __init__.py的内容可以为空,一般用来进行包的某些初始化工作或者设置__all__值,__all__是在from ... import * 语句使用的,__all__中定义的模块将在from ... import * 中全部导入 目

  • Python中__init__.py文件的作用详解

    __init__.py 文件的作用是将文件夹变为一个Python模块,Python 中的每个模块的包中,都有__init__.py 文件. 通常__init__.py 文件为空,但是我们还可以为它增加其他的功能.我们在导入一个包时,实际上是导入了它的__init__.py文件.这样我们可以在__init__.py文件中批量导入我们所需要的模块,而不再需要一个一个的导入. # package # __init__.py import re import urllib import sys impo

  • 浅谈Python __init__.py的作用

    我们经常在python的模块目录中会看到 "__init__.py"  这个文件,那么它到底有什么作用呢? 1. 标识该目录是一个python的模块包(module package) 如果你是使用python的相关IDE来进行开发,那么如果目录中存在该文件,该目录就会被识别为 module package . 2. 简化模块导入操作 假设我们的模块包的目录结构如下: . └── mypackage ├── subpackage_1 │ ├── test11.py │ └── test1

  • 浅谈Python类里的__init__方法函数,Python类的构造函数

    如果某类里没有__init__方法函数,通过类名字创建的实例对象为空,切没有初始化:如果有此方法函数,通常作为类的第一个方法函数,有点像C++等语言里的构造函数. class Ca: def __init__(self, v): # 注意前后各两个下划线 self.name = v def pr(self): print "a--->", self.name ia = Ca("Jeapedu") # 本质调用的是__init__方法函数 ia.pr() Ca.

  • 浅谈Python由__dict__和dir()引发的一些思考

    关于__dict__和dir()的区别和作用请参考这篇文章: 基于Python __dict__与dir()的区别详解 说下我当时遇到的问题: class Demo: def __init__(self, name, age): self.name = name self.age = age def func(self): print('Hello {0}'.format(self.name)) >>> d1 = Demo('Pythoner', 24) >>> has

  • 浅谈python对象数据的读写权限

    面向对象的编程语言在写大型程序的的时候,往往比面向过程的语言用起来更方便,安全.其中原因之一在于:类机制. 类,对众多的数据进行分类,封装,让一个数据对象成为一个完整的个体,贴近现实生活,高度抽象化.但是,python对类的封装并不好,因为所有的属性和方法都是公开的,你可以随意访问或者写入,你可以在类的外部对类的属性进行修改,甚至添加属性.这的确让人感到不安. 下面就来总结一下学习后的解决方案. 1,使用2个下划线前缀隐藏属性或者方法. __xxx #!/usr/bin/python3 #-*-

  • 浅谈python类属性的访问、设置和删除方法

    类属性和对象属性 我们把定义在类中的属性称为类属性,该类的所有对象共享类属性,类属性具有继承性,可以为类动态地添加类属性. 对象在创建完成后还可以为它添加额外的属性,我们把这部分属性称为对象属性,对象属性仅属于该对象,不具有继承性. 类属性和对象属性都会被包含在dir()中,而vars()是仅包含对象属性.vars()跟__dict__是等同的. 类属性和对象属性可类比于Java中的static成员和非static成员,只不python中的类属性和对象属性都是可以动态添加(和删除)的. clas

  • 浅谈python import引入不同路径下的模块

    python 包含子目录中的模块方法比较简单,关键是能够在sys.path里面找到通向模块文件的路径. 下面将具体介绍几种常用情况: (1)主程序与模块程序在同一目录下: 如下面程序结构: `-- src     |-- mod1.py     `-- test1.py 若在程序test1.py中导入模块mod1, 则直接使用 import  mod1或from mod1 import *; (2)主程序所在目录是模块所在目录的父(或祖辈)目录 如下面程序结构: `-- src     |--

  • 浅谈python新手中常见的疑惑及解答

    1 lambda函数 函数格式是lambda keys:express   匿名函数lambda是一个表达式函数,接受keys参数,返回表达式的值.所以不用return,也没有函数名,经常用在需要key参数的函数中,比如sorted. 2 元组(),它是以逗号辨别的,而不是小括号.比如一个元素的元组新手经常写成(12),其实他会被解释成单个元素12.正确的写法应该是(12,),在元素后面加上逗号. 3 模块导入.比如 import random print random.choice(range

  • 浅谈Python中带_的变量或函数命名

    Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就易于阅读,易于在程序员之间交流. python中的标识符可以包含数字.字母和_,但必须以字母或者_开头,其中以_开头的命名一般具有特殊的意义. 前后均带有双下划线__的命名 一般用于特殊方法的命名,用来实现对象的一些行为或者功能,比如__new__()方法用来创建实例,__init__()方法用来初始化对象,

  • 浅谈Python脚本开头及导包注释自动添加方法

    1.开头:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定 #!/usr/bin/python 是用来说明脚本语言是python的 是要用/usr/bin下面的程序(工具)python,这个解释器,来解释python脚本,来运行python脚本的. #!/usr/bin/python:是告诉操作系统执行这个脚本的时候,调用 /usr/bin 下的 python 解释器: #!/usr/bin/env python(推荐):这种用法是为了防止操作系

  • 浅谈Python的方法解析顺序(MRO)

    方法解析顺序, Method Resolution Order 从一段代码开始 考虑下面的情况: class A(object): def foo(self): print('A.foo()') class B(object): def foo(self): print('B.foo()') class C(B, A): pass c = C() c.foo() C同时继承了类A和类B, 它们都有各自的foo()方法. 那么C的实例c调用foo()方法时, 到底是调用A.foo()还是B.foo

随机推荐