一 包介绍
什么是包:包就是一个包含有__init__.py文件的文件夹
mmm/ #顶级包
├── __init__.py
├── n #子包
│ ├── __init__.py
│ ├── a.py
│ └── b.py
└── q.py #子模块
为什么要有包:包的本质是模块的模块的一种形式,包是用来被当做模块导入
强调! 1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错 2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模
二 包的使用
2.1 导入包与__init__.py
导入包时做了三件事:
1、产生一个名称空间
2、运行包下的__init__.py文件,将运行过程中产生的名字都丢到1的名称空间中
3、在当前执行文件的名称空间中拿到一个名字,该名字指向1的名称空间
#包mmm print('运行了。。。。') x=1111 y=2222 def say(): print('hello') #运行文件 import mmm print(mmm.x) print(mmm.y) mmm.say() 例如mmm.x和mmm.y中的x和y都是来自于mmm下的__init__.py,也就是说导入包时并不会导入包下所有的子模块与子包
强调
1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如import 顶级包.子包.子模块,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。 # 例如: from a.b.c.d.e.f import xxx import a.b.c.d.e.f # 其中a、b、c、d、e 都必须是包
2、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
3、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
2.2 绝对导入与相对导入
针对包内的模块之间互相导入,导入的方式有两种
1、绝对导入:以顶级包为起始
#mmm下的__init__.py from mmm import n
2、相对导入:.代表当前文件所在的目录,..代表当前目录的上一级目录,依此类推:要强调的一点是相对倒数.的个数不能超过顶级包的目录
#mmm下的__init__.py from . import n
在包内使用相对导入还可以跨目录导入模块,比如a.py中想引用b.py的名字c
import也能使用绝对导入,导入过程中同样会依次执行包下的__init__.py,只是基于import导入的结果,使用时必须加上该前缀
如:import mmm.n
针对包内部模块之间的相互导入推荐使用相对导入,需要特别强调:
1、相对导入只能在包内部使用,用相对导入不同目录下的模块是非法的
2、无论是import还是from-import,但凡是在导入时带点的,点的左边必须是包,否则语法错误
2.3 from 包 import *
在使用包时同样支持from pool.n import * ,毫无疑问*代表的是n下__init__.py中所有的名字,通用是用变量__all__来控制*代表的意思,他的使用方法和模块中的一样
2.4 环境变量与包
环境变量是以执行文件为准备的,所有的被导入的模块或者说后续的其他文件引用的sys.path都是参照执行文件的sys.path
由于导入包的两种方式中相对导入只用在包的内部,所以我们使用的基本都是绝对导入,而绝对导入是以顶级包为基准的,每个人放包的目录又是不同的,因此最好的方法就是把包导入到环境变量中去。
import sys sys.path.append(r'包的目录')
# 优化方案 import os import sys # print(__file__) # 当前文件的绝对路径 #dirname去除当前文件名后的路径 BASE_DIR=os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR)