95. Python __init__.py 使用

Python工程的组织结构

包、模块、类、函数、变量

  • 最顶级的组织结构:包(文件夹)
  • 第二个层级:模块(文件)
  • 第三个层级:类
  • 第四个层级:函数、变量(不属于组织结构,是类本身的特性)

其中:

  1. 包:整个文件夹
  2. 模块:一个 py 文件

Python包与模块的名字

区分不同包的同名模块:包名.模块名
形成的模块的路径叫做命名空间
一个包下面可以有子包,模块可以和包平级
普通文件夹想要变成包必须要有init.py文件
__init__.py 本身也是一个模块,可以不写内容只是标注包
特殊地,__init__.py 模块的名字就是包名

__init__.py用途

__init__.py 该文件的作用就是相当于把自身整个文件夹当作一个包来管理,每当有外部import的时候,就会自动执行里面的函数。

import导入模块

对于重复的定义需要从其他模块里引用。
利用 import 模块名 导入

1
2
3
4
5
6
# PackageTest1.Test1
a = 1

# PackageTest1.Test2
import Test1
print(Test1.a)

import导入的总是模块,需要用模块名.变量名的方法引用
可以用as简化书写

1
2
3
4
5
6
# PackageTest1.Test1
a = 1

# PackageTest1.Test2
import Test1 as t1
print(t1.a)

同级目录可以直接导入模块
优点是可以一眼看出属于哪个模块

from import 导入变量

1
2
3
# PackageTest1.Test2
from c1 import a
print(a)

可以使用 from 包 import 模块 导入模块
导入时使用 模块.变量
导入大量变量时用 *

1
2
3
4
5
6
7
8
9
10
# PackageTest1.Test1
a = 1
b = 1
c = 1

# PackageTest1.Test2
from Test1 import *
print(a)
print(b)
print(c)

控制 *

1
2
3
4
5
6
7
8
9
10
11
12
# PackageTest1.Test1
__all__ = ['a', 'b']
a = 1
b = 1
c = 1


# PackageTest1.Test2
from Test1 import *
print(a)
print(b)
print(c) # 这里会报错,因为没有导入c

注意

  1. 使用 * 导入时,导入的是在所在包中 __init__.py 存在的变量
  2. 文件目录:

    initTest

    PackageTest1

    __init__.py
    Test1.py

    Test2.py

    Test.py

    其中:

    PackageTest1.__init__.py

    1
    2
    3
    4
    5
    import pandas as pd
    import numpy as np

    print("You have imported mypackage")
    # __all__ = ['pd', 'np'] # 这里不需要 __all__ 控制

    PackageTest1.Test1.py

    1
    2
    3
    4
    5
    6
    7
    from __init__ import * # 可以使用所在包中的 __init__ 导入大量的包

    class Test1():

    def __init__(self):
    a = np.array([i for i in range(10)])
    print(a)

    Test.py

    1
    2
    3
    4
    from PackageTest1 import * # 因为 PackageTest1.__init__ 中只有 pd, np 这两个变量,因此使用 * 只导入进来了 pd, np
    from PackageTest1.Test1 import Test1 # 因为在 PackageTest1.__init__ 中没有 Test1 这个模块,更没有 Test1 这个类,因此想要使用必须自行导入

    Test1()

PackageTest1.__init__ 中导入 Test1 模块、类

  1. 导入 Test1 模块
    PackageTest1.__init__.py中添加 import PackageTest1.Test1 就可以在 Test.py中使用 Test1.Test1() 创建 Test1 类了。
  2. 导入 Test1
    1. PackageTest1.__init__.py中添加 from PackageTest1.Test1 import Test1 就可以在 Test.py中使用 Test1() 创建 Test1 类了。
    2. PackageTest1.__init__.py中添加 import PackageTest1.Test1 是错误的,会报错: ModuleNotFoundError: No module named 'PackageTest1.Test1.Test1'; 'PackageTest1.Test1' is not a package

__init__.py 用法

  1. 当包被导入时,__init__.py 会首先被自动执行,类似于构造函数
  2. __init__.py 的应用场景
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # PackageTest1.__init__.py
    __all__ = ['a','b'] #初始化*

    import sys #批量导入库
    import datetime
    import io


    #Test.py
    import Test1
    print(Test1.sys.path)

    此时引用因为不是用的 * , 所以必须使用 包.类.成员函数 进行调用。

多层目录各层互相调用

pacgage1

__init__.py
test1.py
test2.py

test3.py

test3 调用 package1,而 test1 调用 test2,此时,在 package1.__init__.py 中添加路径,如下:

1
2
import sys
sys.path.append("./package")

包与模块的几个常见错误

  1. 包和模块是不会被重复导入的,只会执行一次(入口文件的概念)
  2. 避免循环导入,不要形成闭环
  3. 导入模块的时候会执行模块里所有的代码
  4. 如果使用 if __name__ == '__main__' 则不会执行该代码块中的代码