第六章 模块

6.1 模块的基本知识

1. 模块的导入

  1. 模块:可以是py文件也可以是文件夹
    • py文件,写好了的对程序员直接提供某方面功能
    • import / from xxx import xx
    • :存储了多个py文件的文件夹,pickle,json,urlib
    • 如果导入一个包,包里默认模块是不能使用的
      • 导入一个包相当于执行__init__.py文件内容
  2. 定义模块时,可以把一个py文件或一个包当作一个模块,以便于以后其他py文件使用。
  3. __ init__.py 在文件夹中创建此py文件, python packages
    • py2:文件夹中必须有__ init__.py
    • py3:不需要,推荐加上
  4. 导入模块
    1. 导入模块—>调用模块中的函数(import 文件名)
    2. import 会把模块中的文件加载到内存
    3. 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)

  1. 模块在和要执行的py文件在同一路径且需要很多功能时,推荐使用import 模块
  2. 其他推荐:from 模块 import 模块
  3. from 模块1.模块2 import 函数 执行:函数()
  4. 文件(夹)命名不可与模块相同,否则就会用当前目录中的文件(夹)
# __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)

  • 内置模块目前有randomhashlibgetpasssys相关,os相关,shutiljsontime&datetime, import lib, logging10个。

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)
  1. random.randint(1,5):包含两边
  2. random.choice([1, 2, 3]):随机选择一个:验证码,抽奖
  3. random.sample([1, 2, 3, 4, 5], 3):随机选3个不重复,抽奖多个人
  4. random.uniform(1, 5):随机1-5中的随机小数
  5. random.shuffle([1,2,3,4]):洗牌,算法
  6. random.random():随机生成[0-1)之间的数
  7. random.randrange(1,5):randint基于randrange

2. hashlib(1) / getpass

摘要算法模块,密文验证/校验文件独立性

note1(3)

  1. md5 / sha
  2. 摘要文件内容一样,无论怎么分割,md5摘要后一致(大文件一致性校验)
  3. 一般在服务端进行加盐,给每个用户使用不同的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)

  • 解释器相关
  1. sys.getrefcount(a)
  2. sys.recursionlimit() / sys.setrecursionlimit()
  3. sys.stdout.write(). print—>进度条
  4. sys.argv:获取命令行参数
    • shutil(shutil.rmtree(path)
  5. sys.path:模块导入路径
  6. 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)

  1. os.path.exist(file_name)
  2. os.stat(file_name).st_size
  3. os.path.abspath(file_name)
  4. os.path.dirname(file_name) # 获取上级目录
  5. os.path.join() # 路径拼接
  6. os.listdir() # 指定目录下的第一层文件,默认path = '.'
  7. os.walk(r'path')
  8. os.mkdir() / os.makedirs()
  9. os.rename(a, b)
  10. os.remove(a)
  11. os.path.isdir()
  12. os.path.isfile()
  13. os.path.isabs()
  14. os.path.basename():获取绝对路径下的文件名
  15. os.getpid():获取进程的id
  16. 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)

  1. shutil.make_archive()
  2. shutil.unpack_archive()
  3. shutil.rmtree()
  4. 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

序列化:将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化

目的

  1. 以某种存储形式使自定义对象持久化
    • 对象持久化是指将内存中的对象保存到可永久保存的存储设备中(如磁盘)的一种技术。
  2. 将对象从一个地方传递到另一个地方。
  3. 使程序更具维护性。

序列化

  • 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)

  1. 经过编码过后的数据,通常称为 字节类型/bytes,字符串,格式为:b‘XXXXXXXX'
  2. 压缩后的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

作用:根据字符串形式导入模块

开放封闭原则:配置文件开放,代码封闭

  1. 使用str导入模块
  2. _import_(和importlib.import_module('模块名'))
  3. 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对像

  1. 创建一个logger对象、文件操作符屏幕操作符格式
  2. 给logger绑定****文件操作和屏幕操作
  3. 给屏幕操作符和文件操作符设置格式
  4. 用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)
posted @ 2019-10-15 21:58  RunningForever  阅读(171)  评论(0编辑  收藏  举报