python之模块
一、模块的定义与分类
1. 模块的定义
- 分文件: 10个文件.每个文件有50个函数,将一些功能相同或相似的函数,放在一个文件中,随用随拿,可以解决代码冗余,重复性,我们应该将这10个函数提取出来,放在一个文件中,随用随拿.
- 一个模块就是一个py文件,这个模块存储很多相似的功能,相似的函数的集合体.
2. 模块的优点
- 节省代码.
- 容易维护,组织结构更清晰.
- 拿来主义,提高开发效率.
3. 模块的分类
- 内置模块,标准库.python解释器自带的,time,os,sys,等等.200多种.
- 第三方库(模块),各种大神写的一些模块,通过pip install....安装.6000种.
- 自己写的模块.自定义模块.
例题
1. 整2个文件,文件1是模块文件,文件2是执行文件
让2调用1中模块进行执行
2. 导入某一个功能或者函数
from xxx import 相当于复制一份过来,容易覆盖当前的变量
整2个文件from tbjx import name
from tbjx import read1
3. change
# 执行文件的效果
from tbjx import name
from tbjx import change
change()
print(name)
# 输出结果
太白金星 # 正常输出的应该是barry
# 模块文件的效果
补全代码
# 3总结:如果引用模块中的函数,如果此函数用到一些变量,这些变量还是从此模块中寻找,不会改变您当前执行文件的变量,这种情况是极值情况(工作中完全用不到)
# 如果你要引用一些模块的变量,你的模块名字 补全内容
流程控制语句__name__之所以能作为流程分流 但脚本运行和模块被引用的时候功能完全不一样
最后一个模块的搜索路径
凭什么我直接import time能找到这个模块
寻找模块的路径 内存—>内置模块—> sys.path中找
二、模块的导入(import)
1.导入方法
# import tbjx
# # 当我引用tbjx模块的时候,实际上将tbjx.py执行一遍,加载到内存.
# import tbjx
# import tbjx
# import tbjx
# import tbjx
# import tbjx
# 只是第一次引用时,将此模块加载到内存.
2.第一次导入模块发生的三件事
- 将tbjx.py文件加载到内存.
- 在内存中创建一个以tbjx命名的名称空间.
- 通过tbjx名称空间的名字.等方式引用此模块的名字(变量,函数名,类名等等).
3.执行方法
模块名加点的方式执行模块功能
import tbjx
n = 1
# print(tbjx.name)
# tbjx.read1()
# tbjx.read2()
4.被导入模块有独立的名称空间
# 坑:通过tbjx.的方式引用此模块的名字时,一定一定是从此模块中寻找.
# 通过import 引用模块 他有自己的独立名称空间,与当前执行文件没有关系.
name = '李业'
print(tbjx.name)
def read1():
print('in 02 模块import')
tbjx.read1()
# 输出结果
太白金星
5.为模块起别名(alias)
优点:
- 简单,便捷.
- 有利于代码的简化
起别名方法
import cStringIO as ci
# 将cStringIO这么长的模块名给他起了个别名,用起来方便
起别名后的调用方法
import 模块名 as 别名 #导入模块中的所有成员
别名.变量名 #调用模块中的一个变量
别名.函数名() #调用模块中的一个函数
模块名.变量名 #错误!!!这样调用将报错!!!
模块名.函数名() #错误!!!这样调用将报错!!!
from 模块名 import 变量名 as 别名1, 函数名 as 别名2
别名1
别名2()
变量名 #错误!!!这样调用将报错!!!
函数名() #错误!!!这样调用将报错!!!
练习题
# 原始写法
result = input('请输入')
if result == 'mysql':
import mysql1
mysql1.mysql()
elif result == 'oracle':
import oracle1
oracle1.oracle()
list.index()
str.index()
tuple.index()
# 起别名
result = input('请输入')
if result == 'mysql':
import mysql1 as sm
elif result == 'oracle':
import oracle1 as sm
''' 后面还有很多'''
sm.db() # 统一接口,归一化思想
# 通过输入不同的数据库名称执行不同的模块中的代码
三、导入多个模块(from…import...)
1.导入和调用方法一
import time
import os
import sys
模块名.变量名 #调用模块中的一个变量
模块名.函数名() #调用模块中的一个函数
2.导入和调用方法二
from tbjx import name # 从tbjx模块导入name功能
from tbjx import read1
from tbjx import read2
print(name)
print(globals())
read1()
变量名 #调用模块中的该变量 直接变量名
函数名() #调用模块中的该函数 直接函数名
注意: 这种方法于在调用时不需要使用前缀,可能会导致其与当前脚本中的成员命名冲突(后出现的成员会覆盖先出现的同名成员),对此可考虑使用别名
3.from ... import ... 与import对比
优点: from.. import 因为不用加模块名用起来更方便
from tbjx import name
print(name)
缺点: 容易与本文件的名字产生冲突
#容易产生冲突,后者将前者覆盖
name = 'alex'
from tbjx import name
print(name)
4.导入模块时的查找顺序
- 内存中:如果这个模块已经成功加载过,就不会重复加载,直接使用内存中的
- 内置路径中:python安装路径下(Lib)
- PYTHONPATH:import时寻找模块的路径。
- sys.path:是一个路径的列表。
- 如果上面都找不到,就报错。
查看被加载的模块
import sys
print(sys.modules)
#输出结果
{'builtins': <module 'builtins' (built-in)>, 'sys': <module 'sys' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, '_imp': <module '_imp' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_thread': <module '_thread' (built-in)>,}
#以字典的形式存在
5.sys.path及将自定义模块导入的方法
获取当前系统中查找模块的路径
import sys
print(sys.path)
#输出结果
['D:\\My Documents\\Pycharm', 'D:\\My Documents\\Pycharm', 'D:\\Program Files\\Python\\python36.zip', 'D:\\Program Files\\Python\\DLLs', 'D:\\Program Files\\Python\\lib', 'D:\\Program Files\\Python', 'D:\\Program Files\\Python\\lib\\site-packages', 'D:\\Program Files\\PyCharm\\helpers\\pycharm_matplotlib_backend']
说明:
- 列表的第一个元素始终是被执行的py文件所在的目录,因此当前py文件所在的路径中的模块始终是可以被直接使用的,第二个元素始终是当前的项目路径
- 系统自带的模块的路径也在其中,这也就说明了为什么在程序中能自由的使用内置模块.
- 系统从前往后依次寻找被导入模块,则路径中如果出现重名的模块,前面的会先生效,这也是为什么我们自定义的模块不要和系统内置的模块同名的原因(将会导致内置模块被覆盖)
值得注意的是,sys.path中出现的路径的子目录并不会被查找到,对此有三种解决方案:
- 把我们自定义的模块放到系统默认的路径中,如D:\Program Files\Python\lib
- 在环境变量中定义PYTHONPATH,在其中保存被导入模块的路径
- 手动修改sys.path表示的列表,将自定义的模块的路径添加到其中
第一种方案并不好,因为会污染系统自带的模块库
第二种方案也不好,因为系统环境变量的改变会影响到其他的项目
第三种方案是通常的做法,既不会污染系统内置路径也不会影响其他项目,只在当前项目中有效.
添加模块路径到默认路径中
假设当前脚本为main.py,想要调用test_module3.py模块中的func3函数
#三步走
#第一步: 先获取当前py文件的绝对路径
print(__file__)
执行结果:
D:/test011/bin/main.py
#第二步: 再获取test_module3.py这个模块的绝对路径
import os
print(os.path.dirname(__file__))
执行结果:
D:/test011/bin
#第三步: 最后拼接,并将模块路径添加
import os
import sys
sys.path.append(os.path.dirname(__file__) + '/dd')
import test_module3
test_module3.func3()
#注:表示地址时,正斜杠“/”与反斜杠“\”可以混用,此例中,将dd前面的"/"改成"\"也行
6.在from 模块名 import *
方式下限制被导入的成员
在被导入的模块中,使用__all__
属性,它是一个列表,其元素是允许被导入的成员名的字符串。注意:此方式对 import 模块名
及其他所有方式的导入都无效。
# 模块中
__all__ = ['f1','f2']
def f1():
print('f1')
def f2():
print('f2')
7.__name__
属性(***)
__name__
是Python内置的一个属性,Python中的函数、模块、类都有这个属性
以脚本方式运行时,__name__
值为__main__
以模块方式被导入时,被导入模块中的__name__
值为模块名(如my_module)
模块中对模块成员的测试代码的通常写法
# b.py
#Pycharm中if __name__ == '__main__':可用main快速输入
def main():
可执行语句1
可执行语句2
……
if __name__ == '__main__':
main()
被别人引用时,名字为模块名(脚本名),脚本方式执行时,名字为main
import b
def a():
pass
b=a
def c():
print(b.__name__)
c()
执行结果:
a
注:可以用__name__显示变量指向内存地址所对应的函数名
四、序列化模块
1.序列化模块的用途
将一种数据结构转换成特殊的序列(特殊字符,bytes),并且还可以转换回去
凡是数据通过网络传出去最终的格式必须bytes
2.json模块
用途: 所有编程语言公认的一种序列,
缺点: 支持的python的数据结构有限,只支持: int str bool dict list tuple None 除了(set())
用法一 (两对儿,四个方法)
dumps,loads # 用于网络传输 #原则一对一,一个dumps对应一个loads
# 转换传输
dic = {'username':'太白'}
ret = json.dumps(dic,ensure_ascill=False,sort_keys=True)
print(ret)
# 反转回来
ret_dict = json.loads(ret)
print(ret_dict)
将转换后的特殊字符串写入文件,再从文件中读取出来,再反转回来
import json
dic = {'username': '太白', 'password': 123,'status': False}
with open('register.json',mode='w',encoding='utf-8') as f1:
ret = json.dumps(dic, ensure_ascii=False)
f1.write(ret+'\n')
with open('register.json',mode='r',encoding='utf-8') as f2:
for line in f2:
ret_dic = json.loads(line)
print(ret_dic)
# 该题练习主题是: 先将转换写入文件,再从文件中读取出来,反转回来
# register.json内容
{"username": "太白", "password": 123, "status": false}
# 输出结果
{'username': '太白', 'password': 123, 'status': False}
用法二
dump,load # 用于单个数据的存取文件,只能用于单个字典,用法很狭窄
import json
dic = {'username': '太白', 'password': 123,'status': False}
with open('jsonlx1.json',encoding='utf-8',mode='w') as f1:
json.dump(dic,f1)
with open('jsonlx1.json',encoding='utf-8') as f1:
dic1 = json.load(f1)
print(dic1,type(dic1))
将多个数据存储到一个文件中
l1 = ['wusir', '太白', '小黑1', 666]
l2 = ['wusir', '太白', '小黑2', 666]
l3 = ['wusir', '太白', '小黑3', 666]
with open('pickle练习1.pickle',mode='wb') as f1:
pickle.dump(l1,f1)
pickle.dump(l2,f1)
pickle.dump(l3,f1)
with open('pickle练习1.pickle', mode='rb') as f1:
ret1 = pickle.load(f1)
ret2 = pickle.load(f1)
ret3 = pickle.load(f1)
print(ret1,ret2,ret3)
3. pickle模块
用途: 支持python的所有类型和数据对象
缺点: 只能python使用
用法一 (两对儿,四个方法)
dumps,loads # 只能是网络传输用,直接转换成bytes
# 转换传输
l1 = ['wusir', '太白', '小黑', 666]
ret = pickle.dumps(l1)
print(ret)
# 反转回来
l2 = pickle.loads(ret)
print(l2)
用法二
dump,load # 用于单个数据的存取文件,只能用于单个字典,用法很狭窄
l1 = ['wusir', '太白', '小黑', 666]
with open('a.pickle',mode='wb') as f1:
pickle.dump(l1,f1)
shevle模块(不讲)
用途: 只能是文件存取,shelve也是python提供给我们的序列化工具,比pickle用起来更简单一些
用法
import shelve
f = shelve.open('shelve_file')
f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'} #直接对文件句柄操作,就可以存入数据
f.close()
import shelve
f1 = shelve.open('shelve_file')
existing = f1['key'] #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错
f1.close()
print(existing)
五、sys模块
用法
import sys
sys.path ***
sys.version
sys.argv
for i in range(3)
print(i)
sys.exit(n) # 强制退出
六、OS模块
用法
import os
print(os.getcwd()) # 获取当前的绝对路径
os.chdir(r'/Users/wuqiang/work/PycharmProjects/python23') # 切换目录 相对于shell下cd
print(os.curdir) # 返回当前路径
# 和文件相关
os.makedirs('目录1/目录2')
os.makedirs('dirname1/dirname2/dirname4') #创建多级目录
os.removedirs('dirname1/dirname2/dirname4') #递归删除多级目录
os.mkdir('abc') #创建单级目录
os.rmdir('abc') #删除单级目录
print(os.listdir('/Users/wuqiang/work/PycharmProjects/python23')) #查看目录下文件类似ls
print(os.stat('/Users/wuqiang/work/PycharmProjects/python23')) #获取状态,文件信息
print(os.environ) #获取环境变量
# 路径相关
print(os.path.abspath('day17.py')) # 获取绝对路径
print(os.path.split(os.path.abspath('day17.py'))) #将文件路径和文件名分割
print(os.paty.dirnaem('day17.py'))
print(__file__) #动态获取当前文件的绝对路径
print(os.path.dirname(os.path.dirname(__file__))) #获取爷爷级目录
print(os.path.basename('day17.py')) #获取文件名
print(os.path.exists('day17.py')) # 判断文件是否存在
print(os.path.isabs('/Users/wuqiang/work/PycharmProjects/python23/day17')) #判断是不是绝对路径
print(os.path.isfile('/Users/wuqiang/work/PycharmProjects/python23/day17')) #判断是不是存在的文件
print(os.path.isdir('day17.py')) #判断是否是一个目录
print(os.path.exists('day17.py')) #判断这个路径或文件是否存在
print(os.path.join('/Users/wuqiang/work/PycharmProjects/python23/day17','day17.py'))#将路径和文件拼接在一起
print(os.path.getatime('/Users/wuqiang/work/PycharmProjects/python23/day17'))#最后访问时间
print(os.path.getmtime('/Users/wuqiang/work/PycharmProjects/python23/day17'))#最后修改时间
print(os.path.getsize('/Users/wuqiang/work/PycharmProjects/python23/day17')) #文件的大小
七、hashlib (加密)
用途: 加密模块,摘要算法,散列算法,它是一堆加密算法的集合
- 密码加密
- 文件的一致性校验
hashlib如何加密:
-
将一个bytes类型的数据,通过hashlib进行加密返回一个等长度的16进制数字
-
过程不可逆
-
相同的bytes类型的数据通过相同的加密码方法得到的数字绝对相同
-
不相同的bytes类型的数据通过相同的加密方法得到的数字绝对不相同
密码加密用法:
ret = hashlib.mkd5()
ret.update('123'.encode('utf-8'))
print(ret.hexdigest())
# 输出结果
202cb962ac59075b964b07152d234b70
获取文件md5值函数写法:
def encryption(path):
import hashlib
ret = hashlib.md5()
with open(path, mode='rb') as f1:
while 1:
content = f1.read(1024)
if content:
ret.update(content)
else:
return ret.hexdigest()
a = encryption('/Users/wuqiang/Downloads/python-3.7.4rc1-embed-win32.zip')
print(a)
#输出结果
加固定盐
ret = hashlib.md5('xxx教育'.encode('utf-8'))
ret.update('123'.encode('utf-8'))
s = ret.hexdigest()
print(s,type(s))
#输出结果
2230499227e2134dc58609d8c8997cd9 <class 'str'>
加动态的盐
username = input('输入用户名:').strip()
password = input('输入密码').strip()
ret = hashlib.md5(username[::2].encode('utf-8'))
ret.update(password.encode('utf-8'))
s = ret.hexdigest()
print(s)
sha系列: 安全系数高,耗时高.加盐,加动态盐
ret = hashlib.sha512()
ret.update('123456fdklsajflsdfjsdlkafjafkl'.encode('utf-8'))
s = ret.hexdigest()
print(s,type(s))