包及绝对,相对导入
概要:
什么是模块 一系列功能的集合 一堆函数放在一个py文件 为什么用模块 提高维护性,可读性,减少代码冗余,使代码组织结构更清晰 四种分类: 1.自定义,包括第三方 2.内置的 3.DLL的c或C++ 4.包 如何使用: import 1.创建名称空间 2.执行模块文件 3.在执行文件中创建一个名称 指向模块的名称空间 from 1.创建名称空间 2.执行模块文件 3.把模块中的名称复制到当前名称空间 两种的区别在于第三步 import m1 m1.func1() from m1 import func1 func1() 注意:避免名称冲突 模块搜索顺序 内存已经加载的 - > 内置的 -> sys.path sys.modules可用查看内存已经加载的 我们经常会操作的是sys.path 两种执行方式: 1.作为执行文件 2.作为模块被导入使用 在代码中可用使用__name__来区分 包 是包含一堆模块的文件夹 本质上就是一个文件夹 不同的是 包中应该包含__init__.py文件 为什么使用包?: 从文件夹级别来组织代码 如何使用: 与使用模块一样 注意:在导入一个包时 实际上导入的是__init__.py init的作用 用于初始化包中的模块 init中主要做什么? 导入包中的模块 包的嵌套 包里面还有包 绝对导入 以执行文件的sys.path为起始点 相对导入 相对于某个模块而言,参照当前所在文件的文件夹为起始开始查找 .表示当前文件 ..表示上一级 ...再上一级 注意:相对导入仅用于包内模块的相互导入 不能超过顶层包 from 导入时 .点的左边必须是一个包名 import 后面必须是一个明确的名字
1.什么是包概念:
包,也是一种模块,对于使用者而言,使用方式和模块没有任何区别。
本质上就是一个文件夹,不同之处在于:多了一个__init__.py文件,叫包的初始化 文件
2.为什么要使用包:
包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来
随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性
3.如何使用包:
import 导入模块时发生了三件事情
1.创建名称空间
2.执行模块py文件,加载名称
3.在执行文件中产生新的名称,指向模块
在导入包的时候,由于包实际上是一个文件夹,所以包中需要提供__init__.py文件,该文件用于代表这个包。
所以import pack,实际是执行了pack下的__init__.py导入这个名称
__init__.py文件的作用
导入该包下的所有模块,这样一来使用包的人,用起来非常简单,无需关心包中的文件结构,只要导入了包,就能使用包中所有功能。
__init__.py文件应该包含哪些内容?
不应该包含任何的业务逻辑,仅仅用于导入包中的模块
注意:所有文件的模块导入都以执行文件sys.path为准
#1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,
在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。
但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。 #2、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件 #3、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
导入包:
import
单独导入包名称时不会导入包中所有包含的所有子模块,如
#在与glance同级的test.py中 import glance glance.cmd.manage.main() #main方法在manage模块中 ''' 执行结果:报错 AttributeError: module 'glance' has no attribute 'cmd' '''
解决办法:
1 #glance/__init__.py 2 from . import cmd 3 4 #glance/cmd/__init__.py 5 from . import manage
执行:
1 #在于glance同级的test.py中 2 import glance 3 glance.cmd.manage.main()
from ... import ...
需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法
1 from glance.db import models-->这是个模块 2 models.register_models('mysql') 3 4 from glance.db.models import register_models-->这是个函数 5 register_models('mysql')
from glance.api import *
在讲模块时,我们已经讨论过了从一个模块内导入所有*,此处我们研究从一个包导入所有*。
此处是想从包api中导入所有,实际上该语句只会导入包api下__init__.py文件中定义的名字,我们可以在这个文件中定义__all___:
#在__init__.py中定义 x=10 def func(): print('from api.__init.py') __all__=['x','func','policy']
绝对导入和相对导入:
我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:
绝对导入:以执行文件的sys.path作为起始点(执行文件只能用绝对导入)
优点:执行文件和被导入的模块中(被导入的模块中可能也会导入别的模块)都可以使用
缺点:所有导入都是以sys.path为起始点,导入麻烦
相对导入:参照当前所在文件的文件夹为起始开始查找(只能在一个包中使用,不能用于不同目录内)
符号:.代表当前所在文件的文件夹,..代表上一级文件夹,...代表上上一级文件夹
优点:导入更加简单
缺点:只能在被导入的模块中使用,不能在执行文件中用,执行文件同级可能有很多文件,导致查找效率低.而包内文件有限,不会存在查找效率问题
例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py #cmd和api属于两个并列文件夹
1 在glance/api/version.py中 2 3 #绝对导入 4 from glance.cmd import manage 5 manage.main() 6 7 #相对导入 8 from ..cmd import manage 9 manage.main()
测试结果:注意一定要在于glance同级的文件中测试
1 from glance.api import versions