python中import学习备忘笔记


Posted in Python onJanuary 24, 2017

前言

在python的模块有两种组织方式,一种是单纯的python文件,文件名就是模块名,一种是包,包是一个包含了若干python文件的目录,目录下必须有一个文件__init__.py,这样目录名字就是模块名,包里的python文件也可以通过包名.文件名的方式import

import语法

import语法有两种

1、直接import模块

import Module
 import Module as xx

2、从模块import对象(下级模块,类,函数,变量等)

from Module import Name
 from Module immport Name as yy

as语法是用来设置对象(这里用对象泛指模块,类,函数等等)别名,import将对象名字引入了当前文件的名字空间

假设有如下目录结构

├── A.py
└── pkg
 ├── B.py
 └── __init__.py

在当前目录下,以下语句都是有效的

import A 
import pkg
import pkg.B
from pkg import B

为了简化讨论,下面将不会对as语法进行举例

import步骤

python所有加载的模块信息都存放在sys.modules结构中,当import一个模块时,会按如下步骤来进行

  1. 如果是import A,检查sys.modules中是否已经有A,如果有则不加载,如果没有则为A创建module对象,并加载A
  2. 如果是from A import B,先为A创建module对象,再解析A,从中寻找B并填充到A的__dict__

嵌套import

在import模块时我们可能会担心一个模块会不会被import多次,假设有A,B,C三个模块,A需要import B和C,B又要import C,这样A会执行到两次import C,一次是自己本身import,一次是在import B时执行的import,但根据上面讲到的import步骤,在第二次import时发现模块已经被加载,所以不会重复import

但如下情况却会报错

#filename: A.py
from B import BB
class AA:pass

#filename: B.py
from A import AA
class BB:pass

这时不管是执行A.py还是B.py都会抛出ImportError的异常,假设我们执行的是A.py,究其原因如下

  1. 文件A.py执行from B import BB,会先扫描B.py,同时在A的名字空间中为B创建module对象,试图从B中查找BB
  2. 扫描B.py第一行执行from A import AA,此时又会去扫描A.py
  3. 扫描A.py第一行执行from B import BB,由于步骤1已经为B创建module对象,所以会直接从B的module对象的__dict__中获取BB,此时显然BB是获取不到的,于是抛出异常

解决这种情况有两种办法,

  1. 将from B import BB改为import B,或将from A import AA改为import A
  2. 将A.py或B.py中的两行代码交换位置

总之,import需要注意的是,尽量在需要用到时再import

包的import

当一个目录下有__init__.py文件时,该目录就是一个python的包

import包和import单个文件是一样的,我们可以这样类比:

  • import单个文件时,文件里的类,函数,变量都可以作为import的对象
  • import包时,包里的子包,文件,以及__init__.py里的类,函数,变量都可以作为import的对象

假设有如下目录结构

pkg
├── __init__.py
└── file.py

其中__init__.py内容如下

argument = 0
class A:pass

在和pkg同级目录下执行如下语句都是OK的

>>> import pkg
>>> import pkg.file
>>> from pkg import file
>>> from pkg import A
>>> from pkg import argument

但如下语句是错误的

>>> import pkg.A
>>> import pkg.argument

报错ImportError: No module named xxx,因为当我们执行import A.B,A和B都必须是模块(文件或包)

相对导入和绝对导入

绝对导入的格式为import A.Bfrom A import B,相对导入格式为from . import Bfrom ..A import B,.代表当前模块,..代表上层模块,...代表上上层模块,依次类推。当我们有多个包时,就可能有需求从一个包import另一个包的内容,这就会产生绝对导入,而这也往往是最容易发生错误的时候,还是以具体例子来说明

目录结构如下

app
├── __inti__.py
├── mod1
│ ├── file1.py
│ └── __init__.py
├── mod2
│ ├── file2.py
│ └── __init__.py
└── start.py

其中app/start.py内容为import mod1.file1

app/mod1/file1.py内容为from ..mod2 import file2

为了便于分析,我们在所有py文件(包括__init__.py)第一行加入print __file__, __name__

现在app/mod1/file1.py里用到了相对导入,我们在app/mod1下执行python file1.py或者在app下执行python mod1/file1.py都会报错ValueError: Attempted relative import in non-package

在app下执行python -m mod1.file1python start.py都会报错ValueError: Attempted relative import beyond toplevel package

具体原因后面再说,我们先来看一下导入模块时的一些规则

在没有明确指定包结构的情况下,python是根据__name__来决定一个模块在包中的结构的,如果是__main__则它本身是顶层模块,没有包结构,如果是A.B.C结构,那么顶层模块是A。

基本上遵循这样的原则

  1. 如果是绝对导入,一个模块只能导入自身的子模块或和它的顶层模块同级别的模块及其子模块
  2. 如果是相对导入,一个模块必须有包结构且只能导入它的顶层模块内部的模块

有目录结构如下

A
├── B1
│ ├── C1
│ │ └── file.py
│ └── C2
└── B2

其中A,B1,B2,C1,C2都为包,这里为了展示简单没有列出__init__.py文件,当file.py的包结构为A.B1.C1.file(注意,是根据__name__来的,而不是磁盘的目录结构,在不同目录下执行file.py时对应的包目录结构都是不一样的)时,在file.py中可采用如下的绝对的导入

import A.B1.C2
import A.B2

和如下的相对导入

from .. import C2
from ... import B2

什么情况下会让file.py的包结构为A.B1.C1.file呢,有如下两种

  1. 在A的上层目录执行python -m A.B1.C1.file, 此时明确指定了包结构
  2. 在A的上层目录建立文件start.py,在start.py里有import A.B1.C1.file,然后执行python start.py,此时包结构是根据file.py__name__变量来的

再看前面出错的两种情况,第一种执行python file1.pypython mod1/file1.py,此时file.py__name____main__ ,也就是说它本身就是顶层模块,并没有包结构,所以会报错

第二种情况,在执行python -m mod1.file1python start.py时,前者明确告诉解释器mod1是顶层模块,后者需要导入file1,而file1.py__name__mod1.file1,顶层模块为也mod1,所以在file1.py中执行from ..mod2 import file2时会报错 ,因为mod2并不在顶层模块mod1内部。通过错误堆栈可以看出,并不是在start.py中绝对导入时报错,而是在file1.py中相对导入报的错

那么如何才能偶正确执行呢,有两种方法,一种是在app上层目录执行python -m app.mod1.file1,另一种是改变目录结构,将所有包放在一个大包中,如下

app
├── pkg
│ ├── __init__.py
│ ├── mod1
│ │ ├── __init__.py
│ │ └── file1.py
│ └── mod2
│ ├── __init__.py
│ └── file2.py
└── start.py

start.py内容改成import pkg.mod1.file1,然后在app下执行python start.py

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者使用python能带来一定的帮助,如有疑问大家可以留言交流。

Python 相关文章推荐
python在Windows8下获取本机ip地址的方法
Mar 14 Python
给Python中的MySQLdb模块添加超时功能的教程
May 05 Python
Java中重定向输出流实现用文件记录程序日志
Jun 12 Python
Python实现的桶排序算法示例
Nov 29 Python
Python测试网络连通性示例【基于ping】
Aug 03 Python
Python类的继承、多态及获取对象信息操作详解
Feb 28 Python
Python OpenCV利用笔记本摄像头实现人脸检测
Aug 20 Python
pytorch中交叉熵损失(nn.CrossEntropyLoss())的计算过程详解
Jan 02 Python
pytorch 图像中的数据预处理和批标准化实例
Jan 15 Python
使用Python开发个京东上抢口罩的小实例(仅作技术研究学习使用)
Mar 10 Python
Python系统公网私网流量监控实现流程
Nov 23 Python
python plt.plot bar 如何设置绘图尺寸大小
Jun 01 Python
用python实现简单EXCEL数据统计的实例
Jan 24 #Python
Python如何import文件夹下的文件(实现方法)
Jan 24 #Python
利用Python脚本实现ping百度和google的方法
Jan 24 #Python
解决python2.7用pip安装包时出现错误的问题
Jan 23 #Python
浅谈终端直接执行py文件,不需要python命令
Jan 23 #Python
在Linux命令行终端中使用python的简单方法(推荐)
Jan 23 #Python
Python 详解基本语法_函数_返回值
Jan 22 #Python
You might like
一个ftp类(ini.php)
2006/10/09 PHP
使用PHP求两个文件的相对路径
2013/06/20 PHP
Laravel 微信小程序后端实现用户登录的示例代码
2019/11/26 PHP
js 异步处理进度条
2010/04/01 Javascript
javascript getElementsByClassName实现代码
2010/10/11 Javascript
jQuery创建插件的代码分析
2011/04/14 Javascript
给jqGrid数据行添加修改和删除操作链接(之一)
2011/11/04 Javascript
JavaScript 5 新增 Array 方法实现介绍
2012/02/06 Javascript
js触发select onchange事件的小技巧
2014/08/05 Javascript
JavaScript快速切换繁体中文和简体中文的方法及网站支持简繁体切换的绝招
2016/03/07 Javascript
关于动态执行代码(js的Eval)实例详解
2016/08/15 Javascript
通过扫描二维码打开app的实现代码
2016/11/10 Javascript
利用vue实现模态框组件
2016/12/19 Javascript
详解Vue2.X的路由管理记录之 钩子函数(切割流水线)
2017/05/02 Javascript
vue2.0多条件搜索组件使用详解
2020/03/26 Javascript
详解angularjs中的隔离作用域理解以及绑定策略
2017/05/31 Javascript
vue router学习之动态路由和嵌套路由详解
2017/09/21 Javascript
vue mint-ui学习笔记之picker的使用
2017/10/11 Javascript
vue.js中ref及$refs的使用方法解析
2019/10/08 Javascript
vue data对象重新赋值无效(未更改)的解决方式
2020/07/24 Javascript
初学python数组的处理代码
2011/01/04 Python
python client使用http post 到server端的代码
2013/02/10 Python
python编写网页爬虫脚本并实现APScheduler调度
2014/07/28 Python
wxpython中自定义事件的实现与使用方法分析
2016/07/21 Python
使用Python正则表达式操作文本数据的方法
2019/05/14 Python
python 如何去除字符串头尾的多余符号
2019/11/19 Python
Python Tkinter Entry和Text的添加与使用详解
2020/03/04 Python
美国独家设计师眼镜在线光学商店:Glasses Gallery
2017/12/28 全球购物
Pam & Gela官网:美国性感前卫女装品牌
2018/07/19 全球购物
关于元旦的广播稿
2014/02/16 职场文书
跳槽求职信范文
2014/05/26 职场文书
乡镇消防安全责任书
2014/07/23 职场文书
食品药品安全责任书
2015/05/11 职场文书
学习计划是什么
2019/04/30 职场文书
浅谈MySQL next-key lock 加锁范围
2021/06/07 MySQL
电频谱管理的原则是什么
2022/02/18 无线电