模块与包

在了解 import 之前,有两个概念必须提一下:

模块: 一个 .py 文件就是一个模块(module)

包: __init__.py 文件所在目录就是包(package)

当然,这只是极简版的概念。实际上包是一种特殊的模块,而任何定义了 __path__ 属性的模块都被当做包。只不过,咱们日常使用中并不需要知道这些。

两种形式的 import

import 有两种形式:

import ...

from ... import ...

两者有着很细微的区别,先看几行代码。

from string importascii_lowercaseimportstringimport string.ascii_lowercase

运行后发现最后一行代码报错:ImportError: No module named ascii_lowercase,意思是:“找不到叫 ascii_lowercase 的模块”。第 1 行和第 3 行的区别只在于有没有 from,翻翻语法定义发现有这样的规则:

import ... 后面只能是模块或包

from ... import ... 中,from 后面只能是模块或包,import 后面可以是任何变量

可以简单的记成:第一个空只能填模块或包,第二个空填啥都行。

import 的搜索路径

提问,下面这几行代码的输出结果是多少?

importstringprint(string.ascii_lowercase)

是小写字母吗?那可不一定,如果目录树是这样的:

./├── foo.py

└── string.py

foo.py 所在目录有叫 string.py 的文件,结果就不确定了。因为你不知道 import string 到底是 import 了 ./string.py 还是标准库的 string。为了回答这个问题,我们得了解一下 import 是怎么找到模块的,这个过程比较简单,只有两个步骤:

搜索「内置模块」(built-in module)

搜索 sys.path 中的路径

而 sys.path 在初始化时,又会按照顺序添加以下路径:

foo.py 所在目录(如果是软链接,那么是真正的 foo.py 所在目录)或当前目录;

环境变量 PYTHONPATH中列出的目录(类似环境变量 PATH,由用户定义,默认为空);

site 模块被 import 时添加的路径1(site 会在运行时被自动 import)。

import site 所添加的路径一般是 XXX/site-packages(Ubuntu 上是 XXX/dist-packages),比如在我的机器上是 /usr/local/lib/python2.7/site-packages。同时,通过 pip 安装的包也是保存在这个目录下的。如果懒得记 sys.path的初始化过程,可以简单的认为 import 的查找顺序是:

内置模块

.py 文件所在目录

pip 或 easy_install 安装的包

相对 import 与 绝对 import

相对 import

当项目规模变大,代码复杂度上升的时候,我们通常会把一个一个的 .py 文件组织成一个包,让项目结构更加清晰。这时候 import 又会出现一些问题,比如:一个典型包的目录结构是这样的:

string/├──__init__.py

├── find.py

└── foo.py

如果 string/foo.py 的代码如下:

#string/foo.py

from string importfindprint(find)

那么 python string/foo.py 的运行结果会是下面的哪一个呢?

按我们前面讲的各种规则来推导,因为 foo.py 所在目录 string/ 没有 string 模块(即 string.py),所以 import 的是标准库的 string,答案是后者。不过,如果你把 foo 当成 string 包中的模块运行,即 python -m string.foo,会发现运行结果是前者。同样的语句,却有着两种不同的语义,这无疑加重了咱们的心智负担,总不能每次咱们调试包里的模块时,都去检查一下执行的命令是 python string/foo.py 还是 python -m string.foo 吧?

相对 import 就是专为解决「包内导入」(intra-package import)而出现的。它的使用也很简单,from 的后面跟个 . 就行:

#from string/ import find.py

from . importfind#from string/find.py import *

from .find import *

我们再看个复杂点的例子,有个包的目录结构长这样:

one/├──__init__.py

├── foo.py

└── two/├──__init__.py

├── bar.py

└── three/├──__init__.py

├── dull.py

└── run.py

from . importdullfrom .. importbarfrom ... importfooprint('Go, go, go!')

改成

from .dull import *

from ..bar import *

from ...foo import *

print('Go, go, go!')

结果是一样的。

那么 python string/foo.py 和 python -m string.foo 的运行结果又是怎样呢?运行一下发现,两者的输出分别是:

Traceback (most recent call last):

File"string/foo.py", line 1, in

from . importfind

ValueError: Attempted relativeimport in non-package

原因在于 python string/foo.py 把 foo.py 当成一个单独的脚本来运行,认为 foo.py 不属于任何包,所以此时相对 import 就会报错。也就是说,无论命令行是怎么样的,运行时 import 的语义都统一了,不会再出现运行结果不一致的情况。

python importlib qpython_Python的import机制相关推荐

  1. python importlib qpython_Python imports指南:Python的导入有更好的理解

    声明:如果你每天写Python,你会发现这篇文章中没有新东西. 这是专为那些像运维人员等偶尔使用Python的人以及那些忘记/误用python import的人写的. 尽管如此,代码是用Python ...

  2. 深入探讨Python的import机制:实现远程导入模块 | CSDN博文精选

    来源 | Python编程时光(ID:Python-Time) 所谓的模块导入,是指在一个模块中使用另一个模块的代码的操作,它有利于代码的复用. 也许你看到这个标题,会说我怎么会发这么基础的文章? 与 ...

  3. 一文搞懂 Python 的 import 机制

    一.前言 希望能够让读者一文搞懂 Python 的 import 机制 1.什么是 import 机制? 通常来讲,在一段 Python 代码中去执行引用另一个模块中的代码,就需要使用 Python ...

  4. python多级目录import_深入理解Python中import机制

    大型项目中为了维护方便,通常使用模块化开发,模块化的过程中,就会涉及到各种包或者模块的相互导入,即使是对于有多个项目的Python开发者来说, import 也会让人困惑!本文带你深入了解python ...

  5. 探究 python import机制、module、package与名字空间

    在开始之前,先了解一个内置函数dir(),它可以帮助我们分析一些内部的东西,dir()的描述是: dir(): 函数不带参数时,返回当前范围内的变量.方法和定义的类型列表:带参数时,返回参数的属性.方 ...

  6. 什么是 Python 的 「内存管理机制」?

    什么是内存管理器(what) Python作为一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言,与大多数编程语言不同,Python中的变量无需事先申明,变量无需指定类型,程序员无需关心内存 ...

  7. Python学习:垃圾回收机制

    Python 程序在运行的时候,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量:计算完成后,再将结果输出到永久性存储器中.如果数据量过大,内存空间管理不善就很容易出现 OOM(out of ...

  8. Python中的字符串驻留机制

    字符串驻留机制(引用计数机制): 字符串驻留是一种在内存中仅保存一份相同且不可变字符串的方法. 系统维护interned字典,记录已被驻留的字符串对象. 对于短字符串,将其赋值给多个不同的对象时,内存 ...

  9. 【Python核心】垃圾回收机制

    Python程序在运行的时候,需要在内存中开辟出一块空间用于存放运行时产生的临时变量,计算完成后再将结果输出到永久性存储器中 如果数据量过大,内存空间管理不善就很容易出现OOM(out of memo ...

最新文章

  1. 画图说明Java String的不变性!可修改字符串不要轻易使用String!
  2. [云炬创业学笔记]第二章决定成为创业者测试11
  3. lvalue-xvalue-prvalue
  4. python正则替换查询_使用Python中的正则表达式进行搜索和替换
  5. Python实现点击选择验证码破解
  6. 白鹭php源码,看源码系列之从运行流程开始-Egret社区-教程文档-白鹭引擎-Egret Engine-免费开源HTML5游戏引擎 - Powered by Discuz!...
  7. CAN通信稳定性开发分析
  8. CSS表格和设置表格样式
  9. ps磁性套索工具如何抠图
  10. 使用 SetParent 跨进程设置父子窗口时的一些问题(小心卡死)
  11. 关于 A/B 测试那些事儿
  12. 主流深度学习框架对比
  13. linux中PS1变量用法
  14. midas nfx 2021 r1
  15. 软考中级系统集成项目管理工程师自学好不好过?
  16. REBOL脚本快速入门
  17. unity3d 2d游戏(太空大战)开发笔记
  18. Flash JEDEC 查看
  19. ESP32学习笔记(20)——SPI(从机)接口使用
  20. linux openal,OpenAL的一些知识点

热门文章

  1. 【重点】LeetCode 24. Swap Nodes in Pairs
  2. atoi函数:c\c++中把字符串整数转换为int型整数
  3. 关于三角函数图像的思考
  4. tf.GraphKeys,tf.add_to_collection() 与 tf.get_collection()
  5. EXCEL VBAProject密码破解 工作表密码破解
  6. 解决Office 365应用程序无法正常启动(0X0000142)
  7. webpack构建工具快速上手指南
  8. linux下mysql 启动命令
  9. Ext 学习之 Store
  10. 946. Validate Stack Sequences验证栈序列