1. 包
包是一种通过 '.模块名'来组织python模块名称空间的形式. 那什么样的东西是包呢? 我
们创建的每个文件夹都可以被称之为包. 但是我们要注意, 在python2中规定. 包内必须存在
__init__.py文件. 创建包的目的不是为了运行, 而是被导入使用. 包只是一种形式而已. 包的本
质就是一种模块
为何要使用包? 包的本质就是一个文件夹, 那么文件夹唯一的功能就是将文件组织起来,
随着功能越写越多, 我们无法将所有功能都放在一个文件中, 于是我们使用模块去组织功能,
随着模块越来越多, 我们就需要一个件夹将模块文件组织起来, 以此来提高程序的结构性和可
维护性
首先, 我们先创建一些包. 用来作为接下来的学习. 包很好创建. 只要是一个文件夹, 有
init__.py就可以 (尽管python3不要求,为了安全起见还是装了比较保险)
import os
os.makedirs('glance/api')
os.makedirs('glance/cmd')
os.makedirs('glance/db')
l = []
l.append(open('glance/__init__.py','w'))
l.append(open('glance/api/__init__.py','w'))
l.append(open('glance/api/policy.py','w'))
l.append(open('glance/api/versions.py','w'))
l.append(open('glance/cmd/__init__.py','w'))
l.append(open('glance/cmd/manage.py','w'))
l.append(open('glance/db/__init__.py','w'))
l.append(open('glance/db/models.py','w'))
map(lambda f:f.close() ,l)
运行上面的代码就会创建一个这样的目录
接着把文件目录对应的文件写进去这些东西
#policy.py def get(): print('from policy.py') #versions.py def create_resource(conf): print('from version.py: ',conf) #manage.py def main(): print('from manage.py')
#models.py
def register_models(engine):
print('from models.py: ',engine)
接下来. 我们在test中使用包中的内容. 并且, 我们导入包的时候可以使用import或者
from xxx import xxx这种形式.
首先, 我们看import
import glance.db.models
glance.db.models.register_models('mysql')
#没问题,可以正常运行
我们还可以使⽤from xxx import xxx 来导入包内的模块
from glance.api.policy import get
get()
也没问题,但是着白要注意的是from xxx import xxx这种形式, import后⾯不可以出现"点" 也
就是说from a.b import c是ok的. 但是 from a import b.c 是错误的
2. __init__
包里的__init__.py是什么鬼? 其实. 不论
我们使用哪种方式导入一个包, 只要是第一次导入包或者是包的任何其他部分, 都会先执行
__init__.py文件. 这个文件可以是空的. 但也可以存放⼀些初始化的代码. (随意在glance中的
__init__.py都可以进行测试)
那我们之前用的from xxx import *还可以⽤么? 可以. 我们要在__init__.py文件中给出
__all__来确定* 导入的内容.
#在__init__文件中
print("我是glance的__init__.py⽂件. ")
x = 10
def hehe():
print("我是呵呵")
def haha():
print("我是哈哈")
__all__ = ['x', "hehe"]
在test文件中
from glance import *
print(x) # OK
hehe() # OK
haha() # 报错. __all__没有这个东西
3 .绝对导入和星对导入
我们的最顶级包glance是写给别人用的. 然
后再glance包内部也会有彼此之间互相导入的需求, 这时候就有绝对导入和相对导入两种
方式了.
1. 绝对导入: 以glance作为起始
2. 相对导入: 以. 或者..作为起始(.当前文件躲在目录, ..当前文件所在目录的上一级目录)
例如, 我们在glance/api/version.py中使用glance/cmd/manage.py
# 在glance/api/version.py #绝对导入 from glance.cmd import manage manage.main()
#相对导入 # 这种情形不可以在versions中启动程序. # attempted relative import beyond top-level package from ..cmd import manage manage.main()
测试的时候要注意. python包路径跟运行脚本所在的目录有关系. 说白了. 就是你运行的
py文件所在的目录. 在python中不允许你运行的程序导包的时候超过当前包的范围(相对导
入). 如果使用绝对导入. 没有这个问题. 换个说法. 如果你在包内使用了相对导入. 那在使用该
包内信息的时候. 只能在包外面导入.
包的注意事项:
1. 关于包相关的导入语句也分为import和from xxx import xxx两种, 但无论使用哪种,
无论在什么位置, 在导入时都必须遵循三个原则: 凡是在导入时d带点的. 点左边都必须是一
个包. 否则报错. 可以带一连串的点. 比如a.b.c
2. import导入文件时. 产生名称空间中的名字来源于文件, import 包, 产生的名称空间
中的名字同样来源于文件, 即包下的__init__,py, 导入包本质就是在导入该文件
3. 包A和包B下有同名模块也不会冲突, 如A.a和B.a来自两个名称空间