导入包与模块

Posted cherry2020

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了导入包与模块相关的知识,希望对你有一定的参考价值。

技术图片
import os
os.makedirs(glance/api)
os.makedirs(glance/cmd)
os.makedirs(glance/db)
ls = []
ls.append(open(glance/__init__.py,w))
ls.append(open(glance/api/__init__.py,w))
ls.append(open(glance/api/policy.py,w))
ls.append(open(glance/api/versions.py,w))
ls.append(open(glance/cmd/__init__.py,w))
ls.append(open(glance/cmd/manage.py,w))
ls.append(open(glance/db/__init__.py,w))
ls.append(open(glance/db/models.py,w))
map(lambda f: f.close() , ls)
View Code

 

技术图片
glance/                   #Top-level package

├── __init__.py      #Initialize the glance package

├── api                  #Subpackage for api

│   ├── __init__.py

│   ├── policy.py

│   └── versions.py

├── cmd                #Subpackage for cmd

│   ├── __init__.py

│   └── manage.py

└── db                  #Subpackage for db

    ├── __init__.py

    └── models.py
View Code

 

技术图片
#各文件内容

#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)
money = 1000

def read1():
    print(from the models->read1->money, money)

def read2():
    print(from the models->read2 calling read1)
    read1()

def change():
    global money
    money = 60
View Code

 

 

 

‘‘‘
层级关系:
test.py
模块名A
包名1/包名2/包名3/模块名B/变量名+函数名
‘‘‘

# 在测试文件test.py中
# 可以写 import 包名1
# 可以写 import 模块名A
# 可以写 from 包名1.包名2 import 包名3
# 可以写 from 包名1.包名2.包名3 import 模块名
# 可以写 from 包名1.包名2.包名3.模块名 import 函数名 或 变量名
‘‘‘
# 错误写法  import 包名.包名.包名.模块名.函数名 或 变量名
# 错误写法  from 包名.包名 import 包名.模块名
‘‘‘


‘‘‘
层级关系:
test.py
包名0/包名1/包名2/包名3/模块名B/变量名+函数名
‘‘‘
# 在测试文件test.py中
# 不可以写 from 包名1.包名2.包名3 import 模块名B
# 不可以写 import 包名1
# python解读此语句后 先进行路径下的模块查找 即从test.py的[sys.path]路径中查找 包名1
# 和test.py所在目录同级的是包名0 因此会报错 ModuleNotFoundError: No module named ‘包名1‘





# 假设以test.py文件的执行 做为程序运行的入口,且当前各__init__.py文件的内容为空
# 此时test.py文件的工作目录路径被写入系统的[sys.path],且作为路径列表中的第一个元素
# 当然,如果你是用PyCharm,PyCharm还会自动补充当前路径的父一级目录 做为[sys.path]路径列表的第二个元素


# "导入工作"的内容1 —— 将被导入的对象 记录于 {sys.modules} 字典
# "导入工作"的内容2 —— 执行文件(包的__init__.py文件 或 模块名.py文件)
# "导入工作"的内容3 —— 创建模块的名字空间 且将‘名字‘导入到执行入口所在的当前名字空间中

# 例1 import glance.db.models 导入的对象是三个 glance  glance.db  glance.db.models
# 例2 from glance.db import models 导入的对象是三个 glance  glance.db  glance.db.models
# 例3 from glance.db.models import register_models 导入的对象还是三个 glance  glance.db  glance.db.models
# 例4 import glance  导入的对象只一个 glance
# 以上例子 我们都显式可见地,仅通过写法就可知{sys.modules}字典中因Import导入新增了哪几个对象
# 你可以用print(sys.modules)去验证,仔细观察你会发现,每个新增对象都从其名字上描述了自己的所属
‘‘‘
glance
glance.db
glance.db.models
‘‘‘
# 这种层级关系的另一处体现是,各包的__init__.py文件 和 模块名.py文件在被执行时,存在了调用先后顺序
# 这里补充一下,.py文件能被python执行的前提是 python能依据路径访问到此文件
# 而路径的成功访问基础是  sys.path + 向下的层级关系
‘‘‘
test.py文件一直是我们执行的入口,在此文件中打印一下sys.path路径列表吧
python是以此路径为基础, 以包和包下模块的层级关系为辅助,访问查找被导入的包或模块的py文件并执行它们的
‘‘‘

# 它们的执行被顺序体现如下
# 例 import glance
‘‘‘
只执行
======glance init 包的初始化========
‘‘‘
# 例 import glance.db.models
# 例 from glance.db import models
# 例 from glance.db.models import register_models
‘‘‘
都遵循下面的执行顺序
======glance init 包的初始化========
======db init 包的初始化========
====models.py==模块文件被执行====
‘‘‘

# 题外话
# 一旦{sys.modules}字典包与包、包与模块间的层级关系的明确
# PyCharm工具软件就可以协助我们在书写代码时,通过按键‘.‘ 关联显示出其备选项
# 例 import glance.db.models
# glance.db.models.register_models(‘mysql‘) 可被通过按‘.‘键被快速写出,且可被执行

‘‘‘
思考问题
test.py文件中 只写import glance
让glance.db.models.register_models(‘mysql‘)在该文件中被成功执行
实践后,你会发现报错 AttributeError: module ‘glance‘ has no attribute ‘db‘
test.py文件中 将import glance 改为 import glance.db.models
再次实践 会发现 glance.db.models.register_models(‘mysql‘)被成功执行
借助两次实践过程中print(sys.modules)的对比结果 你会找到原因
‘‘‘

# 解决办法
# 必须在{sys.modules} 字典中 在只有对象glance的基础上 再补充上如下两个对象 glance.db glance.db.models
# 要写为{sys.modules} 字典新增对象 我们就必须令
# import glance.db  或 from glance import db
# import glance.db.models 或 from glance.db import models
# 这样的语句被执行, 而这样的语句我们又不想写在test.py文件中( 题目是 test.py文件中只写import glance 这一句)
# 那么 我们可以借助包的初始化文件__init__.py的被执行

‘‘‘
# 在glance包的__init__.py文件中 写如下代码
# from glance import db
# 这句代码的执行 使得{sys.modules}字典可以新增 glance.db
# 这句代码的执行 还使得 db包的初始化文件的也被执行
# 因此 我们在db包的__init__.py文件中 再次写如下代码
# from glance.db import models
# 则{sys.modules}字典可以再次新增 glance.db.models
# 且模块文件models.py文件会被执行
# 至此, ‘glance‘  ‘glance.db‘  ‘glance.db.models‘ 这三项都存在于{sys.modules}字典中
# test.py文件中虽只写了一句 import glance,
# 但glance.db.models.register_models(‘mysql‘)已经可以被执行了
‘‘‘


# import"导入工作"结束后的使用,其核心就是 只能使用当前名字空间中新导入的‘名字‘

# 你可以查看globals()
# 你可以借助print(directory()) 对比查看执行入口test.py文件的当前名字空间中名字的变化
‘‘‘
# 例1 import glance 当前名字空间中引入了 一个新名字glance 这是一个包名
# 例2 import glance.db.models 当前名字空间中引入了 一个新名字glance 这是一个包名
# 例3 from glance.db import models 当前名字空间中引入了 一个新名字models 这是一个模块名
# 例4 from glance.db.models import register_models  引入了 一个新名字 register_models 函数名
‘‘‘

# 只要名字存在 该名字就可以被直接拿来使用
‘‘‘
# 针对例1 直接用glance做代码书写的起始开头 如果 {sys.modules} 字典中 glance  glance.db glance.db.models 都存在
# 则可以执行 glance.db.models.register_models(‘mysql‘)
# 针对例2 直接用glance做代码书写的起始开头 glance.db.models.register_models(‘mysql‘)
# 针对例3 直接用models做代码书写的起始开头 models.register_models(‘mysql‘)
# 针对例3 直接用register_models做代码书写的起始开头 register_models(‘mysql‘)
‘‘‘

# 上述代码被执行时,函数register_models都是回到 模块models.py自身的名字空间内执行
# 即模块文件内的函数,都以文件的名称空间做为全局名称空间
# 模块models.py自身的名字空间  对内自称为__main__  对外被称呼为__models__

 

以上是关于导入包与模块的主要内容,如果未能解决你的问题,请参考以下文章

python包与模块导入

导入包与模块

导入包与模块

Python模块包与面向对象综合案例

第 8 章: 模块, 包与分发---PDF版

python:包与异常处理