第六章 模块
6.1 模块的基本知识
1. 模块的导入
- 模块:可以是py文件也可以是文件夹
- py文件,写好了的对程序员直接提供某方面功能
- import / from xxx import xx
- 包:存储了多个py文件的文件夹,pickle,json,urlib
- 如果导入一个包,包里默认模块是不能使用的
- 导入一个包相当于执行__init__.py文件内容
- 定义模块时,可以把一个py文件或一个包当作一个模块,以便于以后其他py文件使用。
- __ init__.py 在文件夹中创建此py文件, python packages
- py2:文件夹中必须有__ init__.py
- py3:不需要,推荐加上
- 导入模块
- 导入模块—>调用模块中的函数(import 文件名)
- import 会把模块中的文件加载到内存
- from py文件名 import func,show… (*):只导入指定函数,也会把模块中的内容加载一遍
- 模块中的函数名可能和本地函数重名
- from 模块 import func as f(模块中的函数重命名) f()
# test为文件夹,在当前工作目录中,jd为py文件,f1为jd中的函数
import test.jd
test.jd.f1()
# test为文件夹,在当前工作目录中,jd为py文件,f1为jd中的函数
from test import jd
jd.f1()
# 导入(绝对导入、相对. /..导入:相对导入必须有父籍包
# import
# from 模块.模块 import 模块
# from 模块.模块.模块 import 函数
# 调用:模块.函数(),函数()
# 主文件:运行的文件(print(__name__)).
if __name__ == '__main__
Note1(4)
- 模块在和要执行的py文件在同一路径且需要很多功能时,推荐使用import 模块
- 其他推荐:from 模块 import 模块
- from 模块1.模块2 import 函数 执行:函数()
- 文件(夹)命名不可与模块相同,否则就会用当前目录中的文件(夹)
# __file__ python命令行中获取的参数
import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(BASE_DIR)
2. 分类(3)
-
内置模块(py内部提供的功能)
-
第三方模块
# pip 安装模块
pip install module_name
# 安装成功,如果导入不成功,需要重启pycharm
- 自定义模块
# a.py
def f1():
pass
def f2():
pass
# 调用自定义模块中的功能
import a
a.f1()
6.2 内置模块(10)
- 内置模块目前有random,hashlib, getpass ,sys相关,os相关,shutil ,json,time&datetime, import lib, logging等 10个。
1. random(7)
# random.randint(a, b)
import random
def get_random_data(length=6):
data = []
for i in range(length):
v = chr(random.randint(65, 90)).lower() # 得到一个随机数
data.append(v)
return ' '.join(data)
- random.randint(1,5):包含两边
- random.choice([1, 2, 3]):随机选择一个:验证码,抽奖
- random.sample([1, 2, 3, 4, 5], 3):随机选3个不重复,抽奖多个人
- random.uniform(1, 5):随机1-5中的随机小数
- random.shuffle([1,2,3,4]):洗牌,算法
- random.random():随机生成[0-1)之间的数
- random.randrange(1,5):randint基于randrange
2. hashlib(1) / getpass
摘要算法模块,密文验证/校验文件独立性
note1(3)
- md5 / sha
- 摘要文件内容一样,无论怎么分割,md5摘要后一致(大文件一致性校验)
- 一般在服务端进行加盐,给每个用户使用不同的salt,可以借助用户名
# 将指定的**str**摘要,可以使用sha1/md5
# md5常用来文件完整性校验
# hashlib.md5()/ .update() /.hexdigest()
import hashlib
def get_md5(data):
obj = hashlib.md5()
obj.update(data.encode('utf-8'))
return obj.hexdigest()
val = get_md5('123')
print(val)
加盐:
import hashlib
def get_md5(data):
obj = hashlib.md5('adsfg12fsg'.encode('utf-8'))
obj.update(data.encode('utf-8'))
return obj.hexdigest()
val = get_md5('123')
print(val)
密码不显示:
import getpass
pwd = getpass.getpass('please input pwd: ')
print(pwd)
3. time(2)
import time
v = time.time() # 获取从1970年开始到目前的时间,单位为秒
time.sleep(2) # 休眠时间,2秒
4. sys (6)
- 解释器相关
- sys.getrefcount(a)
- sys.recursionlimit() / sys.setrecursionlimit()
- sys.stdout.write(). print—>进度条
- sys.argv:获取命令行参数
- shutil(shutil.rmtree(path)
- sys.path:模块导入路径
- sys.modules:存储当前程序中用到的所有模块
# 引用计数器
import sys
a = [1, 2, 3]
print(sys.getrefcount(a))
# python默认支持的递归数量
v = sys.getrecrusionlimit()
# 输入输出,默认换行
sys.stdout.write('hello')
# \n \t
# \r: 回到当前行的起始位置,一般于end=‘’连用
print('123\r', end='')
print('hello', end='')
# 在输出的时候,回到123前,重新打印
# 应用:进度条
- sys.argv / shutil
# sys.argv shutil
# 删除 目录 的脚本, 只能是directory
import sys
import shutil
path = sys.argv[1]
shutil.rmtree(path)
print('remove the %s' % path)
- sys.path(是个list)
- paython解释器会按sys.pathon的路径查找
# sys包含python 和 工作目录
# 当前py文件所在路径会加载到 sys.path中
# pycharm也会 自动添加工作目录 和 项目路径加入
# python导入模块时默认查找路径
# 只能导入目录下的第一层文件
sys.path.append('module_path')
5. os(操作系统相关)(16)
- os.path.exist(file_name)
- os.stat(file_name).st_size
- os.path.abspath(file_name)
- os.path.dirname(file_name) # 获取上级目录
- os.path.join() # 路径拼接
- os.listdir() # 指定目录下的第一层文件,默认path = '.'
- os.walk(r'path')
- os.mkdir() / os.makedirs()
- os.rename(a, b)
- os.remove(a)
- os.path.isdir()
- os.path.isfile()
- os.path.isabs()
- os.path.basename():获取绝对路径下的文件名
- os.getpid():获取进程的id
- os.getppid():获取其父进程的id
import os
1. 获取文件大小
fiel_size = os.stat('filename').st_size # 单位为字节
2. 读取文件
chunk_size = 1024
with open('filename', mode='rb') as f1:
v = r'path' # r 表示转义,包括所有
os.path.dirname(v)
转义
v = 'al\\nex'
v = r'al\nex' # 推荐
import os
v = 'test.txt'
path = 'user/henry/desktop'
new_path = os.path.join(path, v)
# 当前目录下第一层文件
import os
result = os.listdir(r'path')
print(result)
# 当前目录下的所有文件
import os
result = os.walk(r'path') # 生成器
for a, b, c in result:
for i in c: # a 是目录;b 是目录下的文件夹;c 是目录下的文件
path = os.path.join(a, i)
print(path)
6. shutil(4)
- shutil.make_archive()
- shutil.unpack_archive()
- shutil.rmtree()
- shutil.move()
import shutil
shutil.rmtree(r'path')
import shutil
# 没有返回值
shutil.rmtree('dir_name')
# 重命名,可以是文件/目录
shutil.move('file_name1', 'new_file_name')
# 压缩文件(c_file_name.zip), 如果只给定文件名,压缩到py脚本所在目录
shutil.make_archive('c_file_name', 'zip', 'dir_name')
# 解压文件,默认是当前路径, 指定目录不存在会创建文件目录
shutil.unpack_archive('c_file_name.zip', extra=r'dir_paths', format='zip', )
from datetime import datetime
# 当前时间
ctime = datetim.now().strftime('%Y-%m-%d %H:%M:%S')
# 1.压缩test文件夹
# 2.放到code目录(默认不存在)
# 3.将文件解压到/User/henry/Desktop/t中
6.3 json
序列化:将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化。
目的:
- 以某种存储形式使自定义对象持久化
- 对象持久化是指将内存中的对象保存到可永久保存的存储设备中(如磁盘)的一种技术。
- 将对象从一个地方传递到另一个地方。
- 使程序更具维护性。
- json, 所有语言通用,只能序列化指定的基本数据类型
- dumps/loads/ dump/load
- 所有字符串必须都是双引号
- 最外层只能是dict/list
- 不能支持load多次
- dict中key只能是str
- pickle,几乎支持所有python东西(socket对象),序列化的内容只能用python
- dumps/loads/ dump/load
- 支持连续load多次
1. json
# 只能包含,int,bool,str,list,dict
# 最外层必须是list/dict
# json 中如果包含str,必须是 双引号
# 如果是tuple类型数据,则会转换为list
- 特殊的字符串(list和dict嵌套的string)
- 不同语言间的数据交互
- 序列化/反序列化:把其语言的数据转化成json格式/ 相反
import json
v = [12, 3, 4, {'k1': 1}, True, 'adsf']
# 序列化
v = json.dumps(v)
# 反序列化
json.loads(v)
# 可转为json的数据中包含中文,让中文完全显示
v = {'k1': 'alex', 'k2': '你好'}
val = json.dumps(v, ensure_ascii=False)
print(val, type(val))
val = json.dumps(v)
print(val, type(val))
2. pickle
# 使用pickle序列化后,结果是编码后的二进制
import pickle
v = {1, 2, 3}
val = pickle.dumps(v)
print(val, typ(val))
val = pickle.loads(v)
print(val, typ(val))
# json dump 得到的是str, pickle得到的是bytes
Note(2)
- 经过编码过后的数据,通常称为 字节类型/bytes,字符串,格式为:b‘XXXXXXXX'
- 压缩后的0101
6.4 time&datetime
1. time
UTC/GMT:世界协调时间
本地时间:本地时区的时间
- time.time() # 获取时间戳 1970.1.1 00:00-至今 的秒数
- time.sleep(10) # 等待的秒数
- time.timezone # 和标准时间的差距,和电脑的设置有关
2. datetime
# 获取datetime格式时间
from datetime import datetime, timezone, timedelta
v1 = datetime.now()
v2 = datetime.utcnow()
tz = timezone(timedelta(hours = 7)) # 东7区
v3 = datetime.now(tz) # 当前东7区时间
<class 'datetime.datetime'>
# 将datetime格式时间转化为str
v1 = datetime.now()
v1.strftime('%Y-%m-%d') # 连接不能使用汉字(Mac,linux没问题),可以使用.format()方法
# str转datetime,时间加减
val = datetime.strptime('2019-04-18', '%Y-%m-%d')
v = val +/- timedelta(days=40) # 当前时间加/减40天
# 时间戳和datetime关系
import time, datetime
ctime = time.time()
datetime.fromtimestamp(ctime,tz) # 当前时间,tz和上述相同
v = datetime.now()
val = v.timestamp()
print(val)
6.5 模块importlib
作用:根据字符串形式导入模块
开放封闭原则:配置文件开放,代码封闭
- 使用str导入模块
- _import_(和importlib.import_module('模块名'))
- os = _import_('os')和2等价
# 用字符串形式,去对象中找到其成员
import importlib
redis = importlib.import_module('utils.redis')
getattr(redis, 'func')()
import importlib
path = 'utils.redis.func'
module_path, func_name = path.rsplit('.', 1)
getattr(module_path, func_name)()
# 导入模块
import importlib
middleware_classes = [
'utils.redis.Redis',
'utils.mysql.MySQL',
'utils.mongo.Mongo'
]
for path in middleware_classes:
module_path,class_name = path.rsplit('.',maxsplit=1)
module_object = importlib.import_module(module_path) # from utils import redis
cls = getattr(module_object,class_name)
obj = cls()
obj.connect()
# 用字符串的形式导入模块。
# redis = importlib.import_module('utils.redis')
# 用字符串的形式去对象(模块)找到他的成员。
# getattr(redis,'func')()
6.6 日志(模块logging)
日志等级(level) | 描述 |
---|---|
DEBUG | 最详细的日志信息,典型应用场景是 问题诊断 |
INFO | 信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作 |
WARNING | 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的 |
ERROR | 由于一个更严重的问题导致某些功能不能正常运行时记录的信息 |
CRITICAL | 当发生严重错误,导致应用程序不能继续运行时记录的信息 |
1. 日志示例
Note(2)
- 多次配置logging模块,只有第一次配置有效
- 在应用日志时,保留堆栈信息需加上exc_info=True
- 用户:记录日志(银行流水)
- 程序员:统计、故障排除的 debug、错误完成代码优化
# 方法1,
# basicConfig 不能实现中文编码,不能同时向文件和屏幕输出
import logging
# logging.Error 默认级别
logging.basicConfig(fielname='cmdb.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt = '%Y-%m-%d-%H-%M-%S',
level=logging.WARNING,)
logging.log(10, '日志内容') # 不写
logging.debug('asdfgh')
logging.log(30, 'asdfgh') # 写
logging.warning('asdfgh')
应用场景:对于异常处理捕获的内容,使用日志模块将其保存到日志
try:
requests.get('http://www.google.com')
except Exception as e:
msg = str(e) # 调用e.__str__方法
logging.error(msg, exc_info=True) # 线程安全,支持并发
2. logging本质
# 方法2
import logging
# 对象1:文件 + 格式
file_handler = logging.FileHandler('xxxxx', 'a', encoding='utf-8')
fmt = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s')
file_handler.setFormatter(fmt)
# 对象2:写(封装了对象1 )
logger = logging.Logger('xxx(在log中会显示)', level=logging.ERROR)
logger.addHandler(file_handler)
logger.error('你好')
3. 示例
# 推荐
import logging
file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
logging.error('你好')
logger对像
- 创建一个logger对象、文件操作符、屏幕操作符、格式
- 给logger绑定****文件操作和屏幕操作
- 给屏幕操作符和文件操作符设置格式
- 用logger对象操作
# warning和error写入不同文件,需要创建不同对象
import logging
# 需要加入name参数
logger = logging.getLogger()
fh = logging.FileHandler('log.log') # 写入文件
sh = logging.StreamHander() # 不需要参数,输出到屏幕
logger.addHander(fh)
logger.addHander(sh)
# asctime:日志写入时间, name:logger对象名称, levelname:日志级别, module:模块名称
fmt=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s')
fh.Setformatter(fmt)
logger.waring('message')
4. 日志切割
import time
import logging
from logging import handlers
# file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
for i in range(1,100000):
time.sleep(1)
logging.error(str(i))
# 在应用日志时,如果想要保留异常的堆栈信息,exc_info=True
msg = str(e) # 调用e.__str__方法
logging.error(msg,exc_info=True)
6.7 collections
- OrideredDict()
# dict创建过程
info = dict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
- defaultDict
- deque:双端队列
- namedtuple:默认dict,可以给dict的value设置一个默认值
from collections import namedtuple
# 可命名tuple(time 结构化时间)
# 创建了一个Course类,这个类没有方法,所有属性值不能修改
Course = namedtuple('Course', ['name', 'price', 'teacher'])
python = Course('python', 999, 'alex')
print(python)
print(python.name)
print(python.price)
6.8 struct模块
- unpack的结果是元组
- 第一个参数是数据类型
# 把数据转换为四个字节
import struct
a = struct.pack('i', 1000) # bytes 类型
b = struct.pack('i', 78)
a1 = struct.unpack('i', a)
b1 = struct.unpack('i', b)
☞☞☞ 古人学问无遗力,少壮工夫老始成。纸上得来终觉浅,绝知此事要躬行。 ☜ ☜ ☜