Python的import机制
模块与包
在了解 import 之前,有两个概念必须提一下:
- 模块: 一个
.py
文件就是一个模块(module) - 包:
__init__.py
文件所在目录就是包(package)
当然,这只是极简版的概念。实际上包是一种特殊的模块,而任何定义了 __path__
属性的模块都被当做包。只不过,咱们日常使用中并不需要知道这些。
两种形式的 import
import
有两种形式:
import ...
from ... import ...
两者有着很细微的区别,先看几行代码。
from string import ascii_lowercase
import string
import string.ascii_lowercase
运行后发现最后一行代码报错:ImportError: No module named ascii_lowercase
,意思是:“找不到叫 ascii_lowercase 的模块”。第 1 行和第 3 行的区别只在于有没有 from
,翻翻语法定义发现有这样的规则:
import ...
后面只能是模块或包from ... import ...
中,from
后面只能是模块或包,import
后面可以是任何变量
可以简单的记成:第一个空只能填模块或包,第二个空填啥都行。
import 的搜索路径
提问,下面这几行代码的输出结果是多少?
import string
print(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 import find
print(find)
那么 python string/foo.py
的运行结果会是下面的哪一个呢?
<module 'string.find' from 'string/find.py'>
<function find at 0x123456789>
按我们前面讲的各种规则来推导,因为 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 . import find
# 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 . import dull
from .. import bar
from ... import foo
print('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 <module>
from . import find
ValueError: Attempted relative import in non-package
<module 'string.find' from 'string/find.py'>
原因在于 python string/foo.py
把 foo.py
当成一个单独的脚本来运行,认为 foo.py
不属于任何包,所以此时相对 import 就会报错。也就是说,无论命令行是怎么样的,运行时 import 的语义都统一了,不会再出现运行结果不一致的情况。
Python的import机制的更多相关文章
- python 的import机制2
http://blog.csdn.net/sirodeng/article/details/17095591 python 的import机制,以备忘: python中,每个py文件被称之为模块, ...
- 关于Python的import机制原理
很多人用过python,不假思索地在脚本前面加上import module_name,但是关于import的原理和机制,恐怕没有多少人真正的理解.本文整理了Python的import机制,一方面自己总 ...
- 深入探讨 Python 的 import 机制:实现远程导入模块
深入探讨 Python 的 import 机制:实现远程导入模块 所谓的模块导入( import ),是指在一个模块中使用另一个模块的代码的操作,它有利于代码的复用. 在 Python 中使用 ...
- 初窥 Python 的 import 机制
本文适合有 Python 基础的小伙伴进阶学习 作者:pwwang 一.前言 本文基于开源项目: https://github.com/pwwang/python-import-system 补充扩展 ...
- python之import机制
1. 标准 import Python 中所有加载到内存的模块都放在 sys.modules .当 import 一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将 ...
- Python中import机制
Python语言中import的使用很简单,直接使用import module_name语句导入即可.这里我主要写一下"import"的本质. Python官方定义:Python ...
- [转] Python的import初探
转载自:http://www.lingcc.com/2011/12/15/11902/#sec-1 日常使用python编程时,为了用某个代码模块,通常需要在代码中先import相应的module.那 ...
- Python中import的使用方法
源文出处: "import"的本质参照: Python中import机制 python导入自定义模块和包
- python 的 from import 机制
[A.py] from B import D class C:pass [B.py] from A import C class D:pass 为什么执行A的时候不能加载D呢? 如果将A.py改为:i ...
随机推荐
- day3,用户交互,input的应用
1.与用户交互 输入:input() python2.x版本 input后面家的东西要声明输入的类型 >>> input(">>:") ...
- fenby C语言
P1框架 1#include <stdio.h> 2 3int main(){ 4 printf(“C语言我来了”); 5 return 0; 6} P2main()门 P3计 ...
- 完美解决移动端H5页面的滑动穿透问题
同事的分享,记录下来. 代码如下: css: body.modal-open { position: fixed; width: 100%; } js: // 兼容低版本 document.scrol ...
- JavaSE(下)
11.抽象的(abstract)方法是否同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized? 都不能. 抽象方法需要子类重写,而静态的方法是无法被 ...
- Function题解
这个题最优策略一定是向左上走到某一列再往上一直走. n*q在线暴力可做,离线按y排序,单调栈维护凸壳. 具体来说:对于i<j若A[i]>A[j] 即j的斜率小而且纵截距小,一定比i优,并且 ...
- Vue+element UI实现“回到顶部”按钮组件
介绍 这是一个可以快速回到页面顶部的组件,当用户浏览到页面底部的时候,通过点击按钮,可快速回到页面顶部. 使用方法 由于该组件是基于element-UI进行二次封装的,所以在使用该组件时请务必安装el ...
- Linux 学习(1) | 学习方向导图
方向导图 文件系统导图 内核导图
- 推荐Java五大微服务器及其代码示例教程
来源素文宅博客:http://blog.yoodb.com/yoodb/article/detail/1339 微服务越来越多地用于开发领域,因为开发人员致力于创建更大,更复杂的应用程序,这些应用程序 ...
- 你能说说Java中Comparable和Comparator的区别吗
之前面试中被问到这个问题,当时不屑(会)回答,下来特意查了查,整理如下. Java 中为我们提供了两种比较机制:Comparable 和 Comparator,二者都是用来实现对象的比较.排序. 下面 ...
- Mybatis动态语句部分收集
where: <select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BL ...