Packages

一、package

    包是一种通过".模块名"来组织python模块名称空间的方式。我们创建的每个文件夹都可以被称之为包。python2中规定,包内必须存在__init__.py文件。创建包的目的不是为了运行,而是被导入使用。包只是一种形式而已。

  • 本质:一种模块

1.被称之为包所具备的条件:

  • 文件夹
  • 有__init__.py文件(python2中必须有,python3可省略,但最好保留)

2. 导入包时执行的三个动作

  • 判断文件夹是否已经被导入。如果已导入,则不会再重复导入,也就不会执行下面两个操作
  • 开辟一片内存空间,在该空间中执行包的__init__.py文件
  • 创建包的名字。并使用该名称作为该包在当前模块中引用的名字

3. 包的注意事项:

  • 关于包相关的导入语句也分为import和from xxx import xxx两种,但无论使用哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入带点的,点左边都是一个包,否则报错。可以带一连串的点,如a.b.c
  • import导入文件时,产生名称空间中的名字来源于文件。import包,产生的名称空间中的名字同样来源于文件。即包下的__init__.py文件,导入包的本质就是导入该文件。
  • 包A和包B下同名模块也不会冲突。如A.a和B.a来自两个不同的名称空间
  • 导包时,需注意sys.path路径范围,否则易超出范围而报错。
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)

二、包的导入方式

1. import xxx

# 与glance文件夹同目录下test.py
import glance.db.models

glance.db.models.register_models("mysql")


结果:
from models.py:  mysql

2. from xxx import xxx

    采用from xxx import xxx这种形式,import后面不可以出现"."。也就是说,from a.b import c是正确的,而from a import b.c是错误的

# 与glance文件夹同目录下test.py
from glance.db.models import register_models

register_models("mysql")

结果:
from models.py:  mysql

 三、 __init__.py

    不论使用哪种方式导入一个包,只要是第一次导入包或者是包的任何其它部分。都会先执行__init__.py文件。

# glance文件夹下的__init__.py文件
print("我是glance的__init__.py文件")
# 与glance文件夹同目录下test.py
import glance


结果:
我是glance的__init__.py文件

四、绝对导入

    绝对导入,是按sys.path路径寻找包,如果包不在sys.path列表中,可将包移至路径中。也可append包路径到sys.path中,但一般不这样做。

# policy.py
from glance.api.versions import create_resource

def get():
    create_resource("mysql")
    print("from policy.py")
# 与glance文件夹同目录下的test.py
from glance.api.policy import get

get()

结果:
我是glance的__init__.py文件
from version.py:  mysql
from policy.py

五、相对导入

    在相对导入中,python不允许你运行的程序导包的时候超过当前包的范围。

# policy.py
from ..cmd import manage

def get():
    manage.main()
    print("from policy.py")

get()

结果:
ValueError: attempted relative import beyond top-level package

    如果在包内使用了相对导入,那么在使用该包内信息的时候,只能在包外面导入

在包内导入则报错:

# policy.py
from . import versions

def get():
    versions.create_resource("mysql")
    print("from policy.py")

get()

结果:
ImportError: cannot import name 'versions'

在包外导入,运行成功:

# policy.py
from . import versions

def get():
    versions.create_resource("mysql")
    print("from policy.py")
# 与glance文件夹同目录下的test.py
from glance.api.policy import get

get()


结果:
我是glance的__init__.py文件
from version.py:  mysql
from policy.py

 六、单独导入一个包

   单独导入一个包glance,,如果在包中__init__.py文件中并没有关于子包的加载,此时导入的glance什么都做不了。

    在__init__.py中加载子包可以使用绝对路径加载,也可使用相对路径加载

# glance文件夹下的__init__.py文件


from glance import api
# glance/api/__init__.py文件

from glance.api import policy
# glance/api/policy.py

def get():
    print("from policy.py")
# 与glance文件夹同目录下的test.py
import glance

glance.api.policy.get()


结果:
from policy.py

 

posted @ 2018-11-20 16:17  Ethan_Y  阅读(867)  评论(0编辑  收藏  举报