第18天包详解

什么是包?

  包就是一系列模块的集合。本质上就是一个包含了__init__.py文件的文件夹。可以通过pycharm直接创建一个包,也可以自己手动创建一个文件夹,然后再在文件夹里面创建一个__init__.py文件。

包有什么作用

  和模块类似,包就是为了在文件级别上面管理我们创建的模块。

包的使用

  包本质上就是一个模块,因此它的导入和模块的导入方法是完全一样的。不一样的是包内__init__.py的导入方式。

包的注意事项:

#1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:
# 凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。
# 但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
#2、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件 #3、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间

为什么要有__init__.py文件

  我们之前已经解释过了,导入模块有三个步骤,当我们的模块是一个包的时候,我们就会发现到第二步的时候就没法执行了,因为包就是一个文件夹,怎么去执行呢?因此为了使包也可以导入的时候执行,创建了一个__init__.py文件,执行包的时候其实就是执行包下面的__init__.py文件了。然后我们通过__init__.py文件把包内的模块都导入进来,这样我们就可以使用包内的模块了。

1. 执行文件 创建一个命名空间
2. 执行模块文件,创建模块的命名空间
3. 执行文件创建一个名称执行模块的命名空间

验证一:在__init__.py中导入包内的模块的两种模式(此处和正常的导入模块是有区别的)

例如一个包名为:package  
两种方法对于上层的调用都是一样的,都是直接体现为m1
方法一
import  package.m1
方法二
from  package import m1

验证二: 验证导入包的时候就是导入包下面的__init__.py文件

# 这个是一个包pack下面的init文件
print('我是包下面的init文件!')


# 这个是测试包的文件
import pack

# 输出结果是

# 我是包下面的init文件!


这就说明当我们导入包名称的时候,其实执行的是__init__文件

验证三: 验证通过导入包执行模块并不会加入到sys.path的路径中

# 这个是pack包下面的一个m1模块
def sayhi():
    print('hi i am sayhi!')

# 这个是一个包pack下面的init文件
print('我是包下面的init文件!')
import m1


# 这个是测试包的文件
import pack


# 输出会报错
但是包_init__.py文件修改成下面就不会报错
# 这个是一个包pack下面的init文件
print('我是包下面的init文件!')
import pack.m1



这是因为当我执行了测试文件的时候,它只会把当前目录加入到sys.path中,
所以当我们通脱__init__文件去导入m1的时候,系统找不到这个文件,所以报错了

验证四: 验证在__init__.py文件中通过import和from导入的效果是一样的

# 这个是一个包pack下面的init文件
import sys
print('我是包下面的init文件!')
import pack.m1
for i in sys.modules:
    print(i)



# 这个是一个包pack下面的init文件
import sys
print('我是包下面的init文件!')
# import pack.m1
from pack import m1
for i in sys.modules:
    print(i)



# 上面两种出现的结果都是
pack
pack.m1


结论:
1. 在包的__init__.py文件中import和from的行为都是一致的
2. 两种导入方式,都是在当前空间存储了一个pack.xxx
3. 但是为了用户方便,在调用的时候狐狸了pack的存在

相对导入和绝对导入

绝对导入与相对导入

# 绝对导入: 以执行文件的sys.path为起始点开始导入,称之为绝对导入
#        优点: 执行文件与被导入的模块中都可以使用
#        缺点: 所有导入都是以sys.path为起始点,导入麻烦

# 相对导入: 参照当前所在文件的文件夹为起始开始查找,称之为相对导入
#        符号: .代表当前所在文件的文件加,..代表上一级文件夹,...代表上一级的上一级文件夹
#        优点: 导入更加简单
#        缺点: 只能在导入包中的模块时才能使用
      #注意:
        1. 相对导入只能用于包内部模块之间的相互导入,导入者与被导入者都必须存在于一个包内
        2. attempted relative import beyond top-level package # 试图在顶级包之外使用相对导入是错误的,言外之意,必须在顶级包内使用相对导入,每增加一个.代表跳到上一级文件夹,而上一级不应该超出顶级包

绝对导入实例

lianxi(目录)
        good_package(包下面有两个模块和一个包)
            __init__
                from good_package.m1 import * 
                from good_package.m2 import * 
                from good_package.subpack import *
            m1(模块1)
                def f1()
                def f2()
            m2(模块2)
                def f3()
                def f4()
            subpack(包)
                __init__
                    from good_package.subpack.m3 import * 
                m3(模块3)
                    def f5()
        test(执行文件)
            # 需求导入包aaa
            import good_package
            f1()
            f2()
            f3()
            f4()
            f5()

把此实例改成相对导入

    lianxi(目录)
        good_package(包下面有两个模块和一个包)
            __init__
                from .m1 import * 
                from .m2 import * 
                from .subpack import *
            m1(模块1)
                def f1()
                def f2()
            m2(模块2)
                def f3()
                def f4()
            subpack(包)
                __init__
                    from .subpack.m3 import * 
                m3(模块3)
                    from ..m1 import *
                    def f5()
                        f1()
        test(执行文件)
            # 需求导入包aaa
            import good_package
            f1()
            f2()
            f3()
            f4()
            f5()        

  

猜你喜欢

转载自www.cnblogs.com/huwentao/p/9780024.html