Learning-Python【16】:模块的导入使用
一、什么是模块
模块就是一系列功能的集合体,一个模块就是一个包含了Python定义和声明的文件,文件名就是模块名字加上.py的后缀。
模块有三种来源:
1、内置的模块
2、第三方的模块
3、自定义模块
模块的四种通用类别:
1、使用Python编写的代码(.py文件)
2、已被编译为共享库或DLL的C或C++扩展
3、把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
4、使用C编写并链接到Python解释器的内置模块
二、为何要用模块
1、使用内置的或者第三方模块的好处是:拿来就可以使用,可以极大提升开发效率
2、使用自定义模块的好处是:可以减少代码冗余(抽取我们自己程序中要公用的一些功能定义成模块,然后程序的各部分组件都去模块中调用共享的功能)
三、模块的使用
前提:一定要区分开谁是执行文件,谁是被导入模块
1、import导入模块
在Pycharm中右键新建一个文件,文件名是spam.py,模块名是spam,再新建一个文件叫run.py,在run.py中
import spam
首次导入一个模块,会发生以下事情:
1)会产生一个模块的名称空间
2)执行文件spam.py,将执行过程中产生的名字都放到模块的名称空间中
3)在当前执行文件的名称空间中拿到一个模块名,该名字指向模块的名称空间
之后的导入,都是直接引用第一次导入的成果,不会重新执行文件
在spam.py文件中添加代码
money = 1000 def read1():
print('spam模块:',money) def read2():
print('spam模块')
read1() def change():
global money
money = 0
在执行文件中访问模块名称空间中名字的语法:模块名.名字,即在run.py中
import spam print(spam.money) #
print(spam.read1) # <function read1 at 0x000001CE16209B70>
print(spam.read2) # <function read2 at 0x000001CE16209A60>
print(spam.change) # <function change at 0x000001CE16209C80>
spam.read1() # spam模块: 1000 def read1():
print('run.py --> read1') read1() # run.py --> read1 spam.read2() # spam模块
# spam模块: 1000
money = 9999
spam.change()
print(spam.money) #
print(money) #
总结 import 导入模块:在使用时必须加上模块名作为前缀
优点:指名道姓的向某一个名称空间拿取名字,不会与当前名称空间中的名字冲突
缺点:但凡应用模块中的名字都需要加前缀,不够简洁
还可以一行导入多个模块,但不推荐使用
import spam, os, time
可以为模块起别名(注意:模块名应全为小写)
import spam as sm print(sm.money)
print(sm.read1)
2、from...import...导入模块
首次导入模块发生的三件事:
1)创建一个模块的名称空间
2)执行文件spam.py,将执行过程中产生的名字都放到模块的名称空间中
3)在当前执行文件中直接拿到一个名字,该名字就是执行模块中相对应的名字
删除上面的两个文件,重新建一个spam.py,添加代码
money = 1000 def read1():
print('spam模块:',money) def read2():
print('spam模块')
read1() def change():
global money
money = 0
再新建一个run.py,在run.py中
from spam import money print(money) # 1000
from spam import money money = 200
print(money) # 与当前名称空间中的名字冲突, 结果为200
总结from...import...导入模块
优点:使用时,无需再加前缀,更简洁
缺点::容易与当前名称空间中的名字冲突
现在将run.py里的代码改成
from spam import money, read1 money = 200 # 这里执行read1里面的money还是1000,因为在定义阶段就已经固定死了,与调用位置无关
read1() # spam模块: 1000 print(money) #
还可以导入全部模块,但不推荐使用
# 星号代表从被导入模块中拿到所有名字
from spam import *
有一个 __all__ 的功能,将指定的模块名以字符串的形式存放,如果再使用星号导入模块,这时导入的就是 __all__里面的内容,而不是导入全部的模块,例如:
在spam.py中定义 __all__
__all__ = ['money', 'read1'] money = 1000 def read1():
print('spam模块:',money) def read2():
print('spam模块')
read1() def change():
global money
money = 0
在run.py中用星号导入
from spam import * read1() # spam模块: 1000
read2() # 报错, 因为 __all__没有包含read2模块
可以为模块起别名
from spam import read1 as r1 r1()
四、Python文件的两种执行方式
1、直接运行
2、作为模块导入
# 在m1.py中
def f1():
print('f1') print(__name__) # 执行后是 __main__ # 在run.py中
import m1 # 执行后是 m1
即:当做脚本运行,__name__ 等于'__main__',当做模块导入,__name__等于模块名
所以这个条件是:if __name__ == '__main__': ,用来控制.py文件在不同的应用场景下执行不同的逻辑
# 在m1.py中
def f1():
print('f1') if __name__ == '__main__':
f1() # 在run.py中
import m1
五、模块的搜索路径
1、模块搜索路径的优先级
1)内存中已经加载过的
2)内置模块
3)sys.path(第一个值是当前执行文件所在的文件夹)
模块搜索路径优先从内存中已加载过的开始查找,例如我新建一个m1.py和一个run.py,在run.py中导入模块m1
# m1.py
def f1():
print('from f1') # run.py
import time
import m1
time.sleep(10) # 程序睡眠10秒的过程中删除m1.py
import m1
m1.f1() # 这里还可以执行
删除m1.py文件后再导入执行不会报错,因为在删除的过程中程序没有结束,再次导入是优先从内存中查找,找到了直接运行,但如果再次运行就会报错,因为内存已经回收,找不到m1模块了
注意:不应该将自己的模块名命名成与内置模块或第三方模块的名字相同
2、添加sys.path
新建m1.py和run.py,将m1.py放在dir1文件夹下,让dir1文件夹和run.py在同一级目录
# m1.py
def f1():
print('from f1')
f1() # run.py
import m1 # 这时候是找不到的,但是如果添加sys.path,将run.py改成如下
# run.py
import sys
sys.path.append('E://Test//dir1') # 将m1所在的文件夹路径添加到sys.path import m1
3、from...import...
还是上面的情况,可以在run.py里面通过from...import...导入
from dir1 import m1
这是在sys.path中找到的,但是我没有添加sys.path,为什么也能找到呢?
因为sys.path的第一个值是当前执行文件所在的文件夹,也就是Test文件夹(我的run.py和dir1的上一层是Test文件夹),所以说是以当前执行文件的sys.path为准,可以找到dir1,进而找到m1
基于上面的目录,我在dir1下新建一个文件夹叫dir2,在dir2中新建一个文件叫m2.py,现在的路径关系是:Test下面有一个run.py和dir1,dir1下有一个m1.py和dir2,dir2下有一个m2.py
m2中添加代码
def f2():
print('from f2')
f2()
可以通过from...import...导入
from dir1.dir2 import m2
第一种特殊情况:模块的绝对导入
删除上面的所有文件,新建run.py和dir1文件夹,在dir1下新建m1.py和m2.py
# m1.py
def f1():
print('from f1') # m2.py
def f2():
print('from f2')
run想访问m1,因为不在同一级目录,所以要通过上面讲到的两种方法(添加sys.path或from...import导入)来访问(我用后者)
# run.py
from dir1 import m1
现在我执行run.py,可以通过run访问到m1
现在m1想访问m2,只需要在m1中导入m2即可
# m1.py
import m2 def f1():
print('from f1') m2.f2()
但是现在,我再执行run.py,能否通过run访问到m1再访问到m2呢?
不行!因为sys.path是以当前执行文件为准的,那么sys.path的第一个值就是 E://Test//,在m1里面导入m2的时候,去sys.path中无法找到m2,所以会报错
强调:所有被导入的模块参照的环境变量sys.path都是以执行文件为准的
那么怎么解决呢
# m1.py
from dir1 import m2 def f1():
print('from f1') m2.f2() # m2.py
def f2():
print('from f2') # run.py
from dir1 import m1 m1.f1()
注意:不要理解成sys.path是以执行文件所在的文件夹为准,因为sys.path有很多个值,而执行文件所在的文件夹仅仅只是sys.path中的一个值,这个执行文件所在的文件夹找不到后面还有很多值可以找
上面这种情况是以执行文件的sys.path作为参考点开始导入,称之为模块的绝对导入
优点:在执行文件与被导入的模块中都可以使用
缺点:所有导入都是以sys.path为参考点,导入麻烦
第二种特殊情况:模块的相对导入
参照当前所在文件的文件夹为起始开始查找,称之为模块的相对导入
符号:.(一个点)代表当前所在文件的文件夹,..(两个点)代表上一级文件夹,...(三个点)代表上一级的上一级文件夹
优点:导入更加简单
缺点:只能在被导入的模块中使用,不能在执行文件中用
现在在Test下新建一个dir0,dir0下新建一个dir1和run.py,dir1下新建m1.py和m2.py
# run.py
from dir0.dir1 import m1 # 用的还是绝对导入 m1.f1() # m1.py
from . import m2 # 用的是相对导入 def f1():
print('from f1') m2.f2() # m2.py
def f2():
print('from f2')
六、软件开发的目录规范
以 “ATM+购物车” 举例
ATM + 购物车
bin: 整个程序的执行文件,入口(调用核心逻辑的一些功能)
- start.py
conf: 配置文件(程序组件共用的变量)
- settings.py
lib: 库(自定义的模块, 程序组件共用的功能)
- common.py
core: 核心逻辑(与业务相关的逻辑, 购物车的登录注册转账取款等)
- src.py
log: 日志(程序运行产生的关键信息记录)
- transaction.log
db: 数据(数据库相关的文件)
Readme: 读我(软件的介绍, 说明书)
调用业务相关的逻辑应该通过start.py去调取src模块,所以要添加环境变量,然后在start.py中添加代码
# run.py import sys
sys.path.append(r'E:\Python\ATM\core') import src
src.run()
虽然添加core能够让start.py调取到src模块,但可不能这么做。因为以后别人作为软件的使用者,下载了这个软件然后使用,但这里添加的环境变量是开发者自己机器上的文件路径,别人使用时和我肯定不是一样的文件路径,所以无法使用。这时需要让使用者无论在哪个路径下都能使用这个软件,所以要添加一个通用的环境变量,具体做法是添加整个项目的根文件夹。但是这里可不能又写我硬盘上的文件路径,而是让程序自己获取整个项目的根文件夹。
# run.py print(__file__) # 运行
E:/Python/ATM/bin/start.py
__file__可以获取当前执行文件的绝对路径,不同的机器可以获取不同的绝对路径。现在需要获取执行文件所在文件夹的父级文件夹,所以可以基于__file__来获取
os模块有个功能可以获取当前执行文件所在的文件夹的路径
# run.py import os
print(os.path.dirname(__file__)) # 运行
E:/Python/ATM/bin
那么基于上面获取父级文件夹就是再使用一个os.path.dirname
# run.py import os
print(os.path.dirname(os.path.dirname(__file__))) # 运行
E:/Python/ATM
这时便获取到了执行文件所在文件夹的父级文件夹,然后添加到环境变量,以后无论这个软件在哪台机器上运行,都可以得到精准的目录
# run.py import os
import sys BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(BASE_DIR) from core import src src.run()
有一个标准的写法,是将if __name__ == '__main__': 添加进去
# run.py import os
import sys BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(BASE_DIR) from core import src if __name__ == '__main__':
src.run()
Learning-Python【16】:模块的导入使用的更多相关文章
- python 16 模块
目录 模块 1. 自定义模块 1.1 模块分类 1.2 模块的导入 1.3 import 和 from 1.4 from 模块名 import * 1.5 模块的用法: 1.6 导入路径 2. tim ...
- python与模块的导入方式
今日所得 模块 import from...import... 循环导入 相对导入 绝对导入 软件开发目录规范 模块 模块:是一系列功能的集合体 模块的三种来源:1.内置模块(Python解释器自带的 ...
- python之模块的导入
今天在做一个项目的时候卡在模块导入这个点上了.赶紧回头总结一下 一.被导入的文件和工作的脚本在一个目录下 1.导入一个.py文件里的功能或参数(导入模块) 先看一下目录结构: module里有两个功能 ...
- 17.python自定义模块的导入方式
1.直接用import导入 最后运行main.py可以看到命令行窗口输出了一句:你好,这样就完成了. 2.通过sys模块导入自定义模块的路径path 3.在环境变量中找到自定义模块 这个方法原理就是利 ...
- python第三方模块的导入
模块搜索路径 当我们尝试加载一个模块时,Python会在指定的路径下搜索对应的.py文件,如果找不到,就会报错: >>> import module1 Traceback (most ...
- 万恶之源 - Python 自定义模块
自定义模块 我们今天来学习一下自定义模块(也就是私人订制),我们要自定义模块,首先就要知道什么是模块啊 一个函数封装一个功能,比如现在有一个软件,不可能将所有程序都写入一个文件,所以咱们应该分文件,组 ...
- python 浅析模块,包及其相关用法
今天买了一本关于模块的书,说实话,模块真的太多了,小编许多也不知道,要是把模块全讲完,可能得出本书了,所以小编在自己有限的能力范围内在这里浅析一下自己的见解,同时讲讲几个常用的模块. 这里是2018. ...
- Python自定义模块
自定义模块 自定义模块(也就是私人订制),我们要自定义模块,首先就要知道什么是模块 一个函数封装一个功能,比如现在有一个软件,不可能将所有程序都写入一个文件,所以咱们应该分文件,组织结构要好,代码不冗 ...
- python之模块、包的导入过程和开发规范
摘要:导入模块.导入包.编程规范 以My_module为例,My_module的代码如下: __all__ = ['name','read'] print('in mymodule') name = ...
- python中根据字符串导入模块module
python中根据字符串导入模块module 需要导入importlib,使用其中的import_module方法 import importlib modname = 'datetime' date ...
随机推荐
- thymeleaf(一)
(一)Thymeleaf 是个什么? 简单说, Thymeleaf 是一个跟 Velocity.FreeMarker 类似的模板引擎,它可以完全替代 JSP .相较与其他的模板引擎,它有如下 ...
- laravel5.4将excel表格中的信息导入到数据库中
本功能是借助 Maatwebsite\Excel 这个扩展包完成的,此扩展包的安装过程请参考上篇博文:http://www.cnblogs.com/zhuchenglin/p/7122946.html ...
- Eclipse使当前项目依赖另一个项目
实例说明 在Eclipse中可以创建多个项目实现不同的软件开发,也可以使用多个项目来开发单独的大型软件,每个项目负责单独的模块部门,这样可以使软件的模块分类更清晰,可以单独的维护每个模块部分.但是项目 ...
- Oracle课程档案,第七天
数据库管理 关闭数据库有4中方式: 1.shutdown modes 关机模式 2.shutdown normal 关机正常 3.shutdown immediate 立即关闭 ★★ 常用命令 4.s ...
- C语言面试笔记(8/26)
在32位的机器环境下,char.short.int.float.double这样的内置数据类型sizeof值的大小分别为1,2,4,4,8: C++标模板库(standard Template Lib ...
- SQLSERVER 检查内容
巡检内容: 1系统信息A. 机器名称:B. 硬件配置:Intel(R) CPU E5-2630 2.3GHz(2处理器),24核,16G内存C. 操作系统版本:Windows Server 2008 ...
- 《Mysql 数据类型》
一:整型 - 常用类型 类型 占用(字节) 范围 无符号范围 无符号范围 TINYINT 2的8次方 - — — SMALLINT 2的15次方 - — 6553 5 INT 2的31次方 - — 4 ...
- centos7编译安装Python3所需要的库(模块)依赖
在centos中编译安装python3环境,第三方的库 实战的编辑环境: 1.VMware虚拟机 2.centos7 依赖包经过百度搜集以及之前安装Python3报错搜集(centos7反反复复安 ...
- Spark入门到精通--(第一节)Spark的前世今生
最近由于公司慢慢往spark方面开始转型,本人也开始学习,今后陆续会更新一些spark学习的新的体会,希望能够和大家一起分享和进步. Spark是什么? Apache Spark™ is a fast ...
- 14.0-uC/OS-III挂起队列
1.当任务等待信号量. mutex.事件标志组.消息队列时,该任务会被放入挂起队列. 挂起队列是一个OS_PEND_LIST类型的数据结构,它包含了三部分内容. .NbrEntries 挂起队列中有几 ...