1.什么是模块
模块就是一系功能的集合体
模块分为四个通用的类别:我们所用的就是1和3
01 使用python编写的.py文件
02 已被编译为共享库或DLL的C或C++扩展
03 把一系列模块组织到一起的文件夹(注:文件夹下有一个init.py文件,该文件夹称之为包)
04 使用C编写并链接到python解释器的内置模块
模块的三种来源:
01 内置模块
02 第三方模块
03 自定义模块
2.为何要用模块
01 使用内置的或者第三方的模块的好处是,拿来主义,极大的提升开发效率
02 使用自定义模块的好处是将程序各部分组件共用的功能拿出来放到一个模块里面,其他的组件通过导入的方式使用该模块,该模块即自定义的模块,好处是可以减少代码冗余
3.如何用模块
以spam.py为例来介绍模块的使用:**文件名spam.py,模块名spam**
#spam.py
print('from the spam.py')
money=1000
def read1():
print('spam模块:',money)
def read2():
print('spam模块')
read1()
def change():
global money
money=0
import导入文件
首次导入模块会发生三件事
-
会产生一个模块的名称空间
-
执行spam.py文件的内容,将产生的名字丢到模块的名称空间里
-
在当前执行文件中拿到一个名字spam,该名字指向模块的名称空间
money=10#这边就先定义一个一样的变量,下面好做区分
import spam#导入模块
之后的导入直接引用首次导入的成果
import spam
import spam
import spam#之前已经导入过了,所以无须再次导入
使用
print(money)#没有前缀,默认跟当前文件去要
print(spam.money)#1000
print(spam.read1)#<function read1 at 0x00000246064667B8>
print(spam.read2)#<function read2 at 0x00000246064669D8>
print(spam.change)<function change at 0x0000024606466A60>
spam.read1()#spam模块: 1000
def read1():
print('from run1.py read1')
spam.read2()
spam模块
spam模块: 1000
spam.change()
print(money)#10
for...import导入文件
首次导入模块会发生三件事
-
会产生一个模块的名称空间
-
执行spam.py文件的内容,将产生的名字丢到模块的名称空间里
-
在当前执行文件中拿到名字read1,该名字指向模块的名称空间中的read1
from spam import money,read1,read2,change
money=10#这次这个变量定义在导入模块下面
print(money)#10 往全局变量找,找到第一个money就停止了
print(read1)#<function read1 at 0x00000223D10F6950>
print(read2)#<function read2 at 0x00000223D10F6A60>
print(change)#<function change at 0x00000223D10F6AE8>
def read1():
print('from read1')
money=111111
read1()#from read1同样的道理,向上找到函数read1()就停止了
read2()#spam模块
#spam模块: 1000
change()#这里知识改变了模块里面money全局变量的值
print(money)#111111
import总结
优点:指名道姓地问某一个名称空间要名字,不会与当前执行文件名称空间中的名字冲突
缺点:引用模块中的名字必须加前缀(模块名.),使用不够简洁
from...import总结
优点:引用模块中的名字不用加前缀(模块名.),使用更为简洁
缺点:容易与当前执行文件名称空间中的名字冲突
二.模块的搜索路径
查找模块路径的优先级
1 内存
2 内置模块
3 sys.path(是以执行文件为准的,跟导入模块没有关系)
三.如何区分python文件的两种用途
先建一个mmm.py模块
def f1():
print('f1')
def f2():
print('f2')
f1()
f2()
直接运行这个文件会打印出
f1
f2
那么我们在另一个文件中比如就aaa.py中导入这个模块
import mmm
会出现的问题就是我不想他运行出来他也会直接就运行。不大合理,应该我想啥时候调它就啥时候出来,这个时候就有一个内置的变量,解释器会自动给他赋值
print(__name__)
当文件被当作执行文件执行时__name__的值为__main__
当文件被当作模块导入时__name__的值为模块名mmm
def f1():
print('f1')
def f2():
print('f2')
#加上这行代码就可以保证我想它什么时候运行就什么时候运行
if __name__ == '__main__':
f1()
f2()
就比如说我们这个ATM的目录
1 启动文件start.py
# 1. 应该把项目的根目录加到环境变量里
# 2. 应该把项目根目录所在绝对路径拿到,然后加到环境变量里
# sys.path.append(r'D:\脱产5期内容\day15\05 软件开发的目录规范part1\ATM')
from core import src
src.run()
2 整个程序跟业务有关的核心文件src.py
from lib import common
def register():
print('注册。。。')
def login():
print('登陆。。。')
def shopping():
print('购物。。。')
def withdraw():
print('提现。。。')
# 调用日志功能
common.logger('张三提取的一万')
func_dic={
'1':register,
'2':login,
'3':shopping,
'4':withdraw
}
def run():
while True:
print("""
0 退出
1 注册
2 登陆
3 购物
4 提现
""")
choice=input('请输入指令>>>: ').strip()
if choice == '0':break
if choice in func_dic:
func_dic[choice]()
else:
print('请重新输入指令。。。')
3 用户可以指定,配置的文件settings.py
import os BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) LOG_PATH=r'%s\log\transcation.log' %BASE_DIR
4 日志文件 transcation.log
就是记录调用日志功能的地方内容
5 common.py 自定义模块,一些功能就放这里
import time from conf import settings def logger(msg): with open(r'%s' %settings.LOG_PATH,mode='at',encoding='utf-8') as f: f.write('%s %s\n' %(time.strftime('%Y-%m-%d %H:%M:%S'),msg))
6 readme是对这个软件的一些介绍
7 db文件里面发一些信息,比如说用户的账户、密码这些注册信息
五.包
1 什么是包
具体的:包就是一个包含有init.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来
#需要强调的是:
-
在python3中,即使包下没有init.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
-
创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
2 为何要使用包
包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来
随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性
3 注意的事项
1、关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
2、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的init.py,导入包本质就是在导入该文件
3、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间