0%

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
    7
    # PackageTest1.Test1
    a = 1


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

    import导入的总是模块,需要用模块名.变量名的方法引用

    可以用as简化书写

    1
    2
    3
    4
    5
    6
    7
    # 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
    11
    # 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
      3. PackageTest1.__init__.py中添加 from PackageTest1.Test1 import Test1 就可以在 Test.py中使用 Test1() 创建 Test1 类了。
      4. 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__' 则不会执行该代码块中的代码