import 导入问题

Python import导入问题

本文通过对绝对导入和相对导入的机理分析,进而理解Python项目中的常见导入问题, 在理解 import 之前先复习几个概念!

1.sys.modules

sys.modules是一个全局字典, 当某个模块第一次导入,sys.modules会记录该模块,并起到缓冲作用,当第二次重复导入模块的时候,python会直接在此全局字典查找,避免重复导入方法

2.__dict__属性

该属性存储对象的方法和属性,如 self.xxx

3. import 做了什么?

当python import模块的时候, 会生成一个 module对象;并且会检查模块缓存变量 sys.modules

  • import moduleA
    这种方式会检查 sys.modules 中是否有此moduleA模块对象,若有则不重复加载模块。
  • from moduleA import B
    这种方式会先 创建moduleA对象 再加载B 进moduleA的 __dict__ 属性中
4.sys.path

该属性是个列表,存放的是Python 绝对导包的路径集,是第三方模块和应用程序模块的搜索路径

总结 python的导包流程(绝对导入):

当我们在 ‘import sys’ , ‘import requests’ , 'import moduleA’时发生了什么? 这三种 分别是 标准库、第三方模块 、本地应用程序模块,这三种包含了所有导包的场景.

  1. Python会首先在 sys.modules 中搜索 sys 模块,若 此缓存中有该模块,则将缓存内容直接返回,导入结束;
  2. 若缓存中没有该模块,则Python会先搜索 自己的标准库,sys是Python的标准库,所以到此模块导入动作结束,而requests 和 moduleA 此时继续执行第三步;
  3. 此时会搜索 sys.path,这是Python 绝对导包的 搜索路径,列表格式,路径有优先级,索引靠前的优先级高;
  4. Python为 模块在本地作用域 简历 module 对象,模块导入完成

ps: Python2.4之后已经取消了隐式相对导入这个机制,延伸_ 什么是隐式相对导入?

案例说明

root_path
|---c.py
|---import_demo/
	|---__init__.py
	|---a.py
	|---os.py
	|---requests.py

a.py

import os  # 此时 会导入标准库的os模块,不会导入同级目录下的 os模块, 而在python2.4会导入 同级目录下的os
import requests  # 此时导入

绝对导入

# 绝对导入的两种方式
import moduleA
from moduleA import *
1.此时若 moduleA 为标准库的

相对导入

# 相对导入只能通过  from xx import xx 的方式
from . import B  # 从当前目录导入B
from .. import B # 从上级目录导入B

导包场景测试

环境 Python3.7, 2.7
在这里插入图片描述

root_path
|---import_demo/
	|---__init__.py
	|---a.py
	|---os.py
	|---requests.py
	|---inner/
		|---__init__.py
		|---inner_test.py

a.py

import os
import requests

from inner_package import *

os.py

print('This is os module')

requests.py

print('This is requests module')

inner/init.py

# 第一种
import test
# 第二种
from test import *
# 第三种
from . test import *  

inner/inner_test.py

print('This is test module')
说明☆
Python 2.7 和3.7 执行情况说明

a是执行文件,即import_demo为顶层目录,此时在a.py中不允许相对导入存在,两种导包方式: import xx / from xx import xx 都为绝对导入形式,此时除了Python的标准库外,其余包会严格按照 sys.path这一 PYPATHON 环境变量映射 顺序 来执行,此时的现象是:
在这里插入图片描述

  1. 因为 os为标准库,requests 为 第三方库 所以此时 os会执行标准库导入,而requests会执行 sys.path顺序导入,在这个列表中 当前目录的优先级最高,所以会覆盖掉 第三方库的模块;
  2. 在 inner 包的 init.py 中执行三种导包方式 都可以导入 test模块,因为 2.7版本 默认是 执行相对导入的,而在 Python3.7 版本执行 第一种和第二种方式会报错,只有宝贝执行第三种相对导入才会正常执行,因为 python3.7 默认执行 绝对导入,即搜索sys.path列表中的路径
    在这里插入图片描述
总结:
  • Python2.x默认执行 相对导入 Python3.x 默认执行绝对导入;

  • 相对导入的概念 只在包内导入有效,顶层脚本执行如果有相对导入格式的代码会报错,顶层脚本的非标准库模块导入严格执行 sys.path
    在这里插入图片描述
    重点之-相对导入
    相对导入与 模块属性 __name__有关
    如下目录结构

    
    mypackage/
      __init__.py
      A/
          __init__.py
      	   a.py
      B/
          __init__.py
      		b.py
      run.py
    main.py
    

    若 以 run.py 作为启动文件,则此时有

    • run.py 的 __name__ 为 __main__
    • a.py 的 __name__ 为 A.a
      此时A成为顶层的包,所以相对导入最多​只能访问到A,A之外的层次结构是不可见的

    若以 main.py 作为启动文件,则此时有

    • main.py 的 __name__ 为 __main__
    • a.py 的 __name__ 为mypackage.A.a
      mypackage成为顶层包,相对导入作用域扩大,B/包对a.py可见

    即: 相对导入只适用于包中的模块,顶层的模块中将不起作用

  • 在Python2.x版本中,若要在包内进行导入,可以用 非相对导入的形式进行相对导入。如 import xx 或者 from xx import xx,而非必须 from . import xx 这种形式

  • python 2.x和python 3.x的导包机制
    在这里插入图片描述

  • 顶层脚本导入 与标准库同名的os模块,此时会执行标准库的导入,而非当前目录的os模块,而包内导入 与标准库同名的os模块,则会以当前目录的os模块为准,即有如下目录结构

root_path
|---import_demo/
   |---__init__.py
   |---a.py
   |---os.py
   |---requests.py
   |---inner/
   	|---__init__.py
   	|---inner_test.py
   	|---os.py

a.py

import inner

inner/init.py

import os

inner/os.py

print('This is my os module')

执行 a.py 结果 :(注:此只在 2.x版本有效 3.x版本取消了 这种相对导包方式)
在这里插入图片描述

  • Python2.x与Python3.x导包方面只在 包内导包默认方式上的区别,暂未遇到其他
最后强调

Python2.x版本会在 2020.1.1 停止更新,所以后续的更新会以3.x版本为准,新入手的 pythoner 请以3.x版本为准进行学习!

发布了14 篇原创文章 · 获赞 3 · 访问量 705
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览