__init.py__是做什么用的?

February 27, 2024

© 2024 borui. All rights reserved. This content may be freely reproduced, displayed, modified, or distributed with proper attribution to borui and a link to the article: borui(2024-02-27 12:11:26 +0000). __init.py__是做什么用的?. https://borui/blog/2024-02-27-zh-what-is-init-py-for.
@misc{
  borui2024,
  author = {borui},
  title = {__init.py__是做什么用的?},
  year = {2024},
  publisher = {borui's blog},
  journal = {borui's blog},
  url={https://borui/blog/2024-02-27-zh-what-is-init-py-for}
}

the funtions of __init__.py/ what is init py for?

1. 概述

在python中经常能看到__init__.py文件,似乎没什么用的样子,有的时候甚至直接是空的,那么这个文件到底有什么用呢?

对于一个python项目,里面的每一个文件夹都可以认为是一个package,而每一个.py文件被认为是一个module。如果你用的IDE是PyCharm,那么当你新建一个Python Package的时候,PyCharm都会自动为你新建一个__init__.py文件。这个__init__.py文件可以看作这个package的初始化文件,具体用途且看下文。

💡 Tip: python3.3以后不需要空的__init__.py了。如果你一定需要只能具体某些模块被包含进这个包,而不是所有的模块都包含进这个包,那么必须加__init__.py来指定。

2. init.py文件在做什么?

要了解__init__.py有什么用,首先要理解他在坐什么?我们举一个简单的例子:

文件目录如下

.
├── demo.py
├── package
|   ├── __init__.py
|   ├── module.py
# ./demo.py
import package

# ./pacakge/__init__.py
print("__init.py file is called!")

那么当我执行demo.py文件时,输出结果如下

$ python demo.py 
__init.py file is called!

这说明__init__.py中的代码被执行了。如果把demo.py中的 import package 换成import package.module也是一样的结果。这说明,当我们从一个package里面调用东西的时候,该__init__.py文件内的代码会被首先执行。

3. init.py文件有什么用?

3.1 简化import语法

假设在module.py文件中有一个函数a_function()如下

# ./pacakge/module.py
def a_function():
    print("Test function is called!")

如果我现在想从demo.py中调用它,没有__init__.py文件的话,只能这么写(方法一)

# ./demo.py
from package.module import a_function
a_function()

但是我可以在__init__.py中进行如下定义

# ./pacakge/__init__.py
from package.module import a_function

这样定义完了以后在demo.py就可以如下调用了(方法二)

# ./demo.py
from package import a_function
a_function()

好像也没简洁到哪儿去?试想,如果你在package里面有几十个module,那么当你想调用这几十个module里面的几十上百个函数的时候,你就需要在demo.py文件中写几十行import语句,这样无疑是不简洁的。而采用方法二的办法,你就可以把这些import语句统统放进__init__.py文件。但这不是__init__.py最重要的用途,最重要的是下面两点。

3.2 批量导入和规范化导入以及__all__

如果你在module.py中定义了很多函数,你想在demo.py中调用,怎么办呢?如module.py中有两个函数

# ./pacakge/module.py
def a_function_1():
    print("Test function 1 is called!")
def a_function_2():
    print("Test function 2 is called!")
# 先在__init__.py批量导入
# ./pacakge/__init__.py
from package.module import *

# 再在demo.py中批量导入
# ./demo.py
from package import *
a_function_1()

这样就可以实现package中诸多函数的批量导入了。注意批量导入遵从覆盖原则,即如果有多个类和方法名字相同,那么后导入的会覆盖先导入的。 但是如果你只允许a_function_1被外界调用呢,就可以把__init__.py改成

# 这样在demo.py文件中,调用a_function_2就会报错。

from package.module import a_function_1

# ./demo.py
from package import *
a_function_2()    # 这里就会报错

更优雅一点可以调用__all__属性,在__init__.py中定义可以被外界调用的类和方法,如

# ./pacakge/__init__.py
__all__ = ['a_function_1']     # 这样,在demo.py只能调用a_function_1方法
from package.module import *

这里举的例子都是函数/方法,对于类来说,是一样的。

3.3 import倒入一个包的时候,它的子包不会被自动导入

此外的此外,添加__init__.py的好处还有:一般当你用import倒入一个包的时候,它的子包不会被自动导入,除非你在__init__.py里显式地import 一下。举例如下:

$ mkdir -p a/b
$ touch a/b/c.py

这命令行输入python打开交互式python界面:

import a
a                 <module 'a' (namespace)>
a.b              ⇒ AttributeError: module 'a' has no attribute 'b'
import a.b.c
a.b              ⇒ <module 'a.b' (namespace)>
a.b.c            ⇒ <module 'a.b.c' from '/home/cjs/a/b/c.py'>

单独import a 不会自动导入a.b.c。但是单独import a.b.c会自动导入父包a和a.b。 但是一旦你在a这个文件夹下新建__init__.py并且写入import b

这时候

import a
a                 <module 'a' (namespace)>
a.b              ⇒  <module 'b' (namespace)>
  1. 无尘粉笔. (2 Mar, 2022.). 【python】init.py文件到底是什么?. 知乎专栏. [Blog post]. Retrieved from https://zhuanlan.zhihu.com/p/474874811

  2. Ordgod_new. (28 Oct, 2020.). python构建包和模块的时候要不要加__init__.py?. CSDN. [Blog post]. Retrieved February 27, 2024, from https://blog.csdn.net/weixin_41490373/article/details/109324834