文章目录
一、time与datetime模块
- 时间分为3种格式
- 时间戳: 从1970到现在经过的秒数
- 作用:用于时间间隔的计算 - 按照某种格式显示的时间: 例如:2021-01-01 11:11:11
- 作用: 用于展示时间 - 结构化的时间
- 作用: 主要用于获取当前时间的某一部分
- 时间戳: 从1970到现在经过的秒数
import time
from datetime import datetime, timedelta
# - time
# 1. 获取时间戳:
print(time.time())
# 2. 按照某种格式显示的时间: 例如:2021-01-01 11:11:11, 作用:
print(time.strftime("%Y-%m-%d %H:%M:%S %p"))
print(time.strftime("%Y-%m-%d %X"))
# 3. 结构化的时间
res = time.localtime()
print("结构化的时间:", time.localtime())
print(res.tm_mday)
- datetime
# - datetime
# 第二种格式化的时间是最常用的时间形式, datetime擅长的
print(datetime.now())
# 时间的加减
res = datetime.now() + timedelta(weeks=+2, seconds=+120)
print("加后的时间:", res)
res = datetime.now() + timedelta(days=-3)
print("减后的时间:", res)
# 需要掌握的操作
# 一、时间格式的转换
# struck_time(结构化时间) -> 时间戳
s_time = time.localtime()
print(s_time)
print(time.mktime(s_time))
# 时间戳 -> struck_time
tp_time = time.time()
print(time.localtime(tp_time))
print(time.gmtime()) # 世界标准时间,差8个小时, 我们用的是北京时间,上海时区
# struck_time -> 结构化的字符串的时间
s_time = time.localtime()
print(time.strftime("%Y-%m-%d %H:%M:%S", s_time))
# 结构化的字符串的时间 -> struck_time
print("结构化的字符串的时间转化为struck_time:", time.strptime("2021-01-01 11:11:11", "%Y-%m-%d %H:%M:%S"))
# 真正常用的只有一点:结构化的字符串的时间 -> timestamp
# 需求 + 7
s_text = "2021-01-01 11:11:11"
res = datetime.strptime(s_text, "%Y-%m-%d %X") + timedelta(days=7)
print("结果:", str(res))
print(type(str(res)))
3 . 其他知识
# 其他知识
time.sleep(1) # 爬虫重要
print(time.asctime()) # 通常用于linux
print(datetime.utcnow()) # 世界标准时间
print(datetime.fromtimestamp(time.time()))
二、random模块
- 用来去随机值的
import random
print("大于0且小于1之间的小数: ", random.random()) # (0,1)----float
print("大于等于1且小于等于3之间的整数: ", random.randint(1, 3)) # [1,3]
print("大于等于1且小于3之间的整数: ", random.randrange(1, 3)) # [1,3)
print("1或者23或者[4,5]: ", random.choice([1, '23', [4, 5]])) # 1或者23或者[4,5]
print("列表元素任意2个组合: ", random.sample([1, '23', [4, 5]], 2)) # 列表元素任意2个组合
print("大于1小于3的小数: ", random.uniform(1, 3)) # 大于1小于3的小数,如1.927109612082716
item = [1, 3, 5, 7, 9]
random.shuffle(item) # 打乱item的顺序,相当于"洗牌"
print("打乱item的顺序,相当于'洗牌': ", item)
# 随机验证码
res = ''
for i in range(6):
s1 = chr(random.randint(65, 90)) # 字母
s2 = str(random.randint(0, 9)) # 数字
res += random.choice([s1, s2])
print(res)
三、os模块
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') 可生成多层递归目录
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename("oldname","newname") 重命名文件/目录
os.stat('path/filename') 获取文件/目录信息
os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示
os.environ 获取系统环境变量
os.path.abspath(path) 返回path规范化的绝对路径
os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) 如果path是绝对路径,返回True
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
os路径处理
#方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
os.path.abspath(__file__),
os.pardir, #上一级
os.pardir,
os.pardir
))
sys.path.insert(0,possible_topdir)
#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# 在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
>>> os.path.normcase('c:/windows\\system32\\')
'c:\\windows\\system32\\'
#规范化路径,如..和/
os.path.normpath('c://windows\\System32\\../Temp/')
'c:\\windows\\Temp'
a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
print(os.path.normpath(a))
/Users/jieli/test1
四、sys模块
- 基础函数功能说明
1 sys.argv 命令行参数List,第一个元素是程序本身路径
2 sys.exit(n) 退出程序,正常退出时exit(0)
3 sys.version 获取Python解释程序的版本信息
4 sys.maxint 最大的Int值
5 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
6 sys.platform 返回操作系统平台名称
- python test.py 参数, 运行时候传递与接收参数, 实现: cp 源文件路径, 目标文件路径
# 需求: 在python test.py 的时候传一些参数, 如何拿到这个参数
import sys
# 获取解释器传入的参数, 在程序中就可以按照索引取出想要的参数值
print(sys.argv) # ['test.py', '1', '2', '2']
# 应用需求: 写一个程序, 完成文件copy
# 原来解决方式
# src_file = 'C:/project/code/insertdata/read_test.txt'.strip()
# dst_file = 'C:/project/code/insertdata/read_test1.txt'.strip()
src_file = input('源文件路径:').strip()
dst_file = input('目标文件路径:').strip()
with open(r'%s'%src_file, mode='rb') as read_f, open(r'%s'%dst_file, mode='wb') as write_f:
for line in read_f:
write_f.write(line)
# 新解决办法
res = sys.argv
src_file = res[1]
dst_file = res[2]
with open(r'%s'%src_file, mode='rb') as read_f, open(r'%s'%dst_file, mode='wb') as write_f:
for line in read_f:
write_f.write(line)
- python打印进度条
import time
# 指定宽度
print('[%-15s]' %'#') # -:左对齐, 固定宽度50
print('[%-15s]' %'##')
print('[%-15s]' %'###')
print('[%-15s]' %'####')
res = ''
for i in range(50):
res += '#'
time.sleep(0.5)
print('\r[%-50s]' % res, end='') # 每次打印都是从行首
def progress(precent):
if precent > 1:
precent = 1
res = int(precent * 50)
print('\r[%-50s] %d%%' % ('#' * res, int(100 * precent)), end='')
recv_size = 0
total_size = 33333
while recv_size < total_size:
time.sleep(0.2) # 下载1024个字节的数据
recv_size += 1024
# 打印进度条
precent = recv_size / total_size
progress(precent)
五、shutil模块
- 文件的操作,主要看下面的知乎专栏
六、json&pickle模块(序列化和反序列化)
- 序列化和反序列化
- 什么是序列化和反序列化
-
内存中的数据类型 -----> 序列化 -----> 特定的格式(json或者pickle格式)
-
内存中的数据类型 <----- 反序列化 <----- 特定的格式(json或者pickle格式)
-
土办法:
- {‘aaa’: 111} -----> 序列化str({‘aaa’: 111}) -----> “{‘aaa’: 111}”
- {‘aaa’: 111} <----- 反序列化eval({‘aaa’: 111}) <----- “{‘aaa’: 111}”
- 为何要序列化
- 序列化得到的结果=》特定格式的内容有两种用途
- 可用于存储=》相当于存档
- 传输给其他平台使用=》跨平台数据交互
# python java
# 列表 特定的格式 数组
import json
# 示例一
# 序列化
json_res = json.dumps([1, 'aaa', True, False])
print(json_res, type(json_res))
# 反序列化
l = json.loads(json_res)
print(l, type(l))
# 示范二
# 序列化结果写入文件的复杂方法
json_res = json.dumps([1, 'aaa', True, False])
with open('test.json', mode='wt', encoding='utf-8') as f:
f.write(json_res)
# 序列化的结果写入文件的简单方法
with open('test.json', mode='wt', encoding='utf-8') as f:
res = [1, 'aaa', True, False]
json.dump(res, f)
# 从文件读取json格式的字符串的进行反序列化操作的复杂方法
with open('test.json', mode='rt', encoding='utf-8') as f:
json_res = f.read()
l = json.loads(json_res)
print(l, type(l))
# 从文件读取json格式的字符串的进行反序列化操作的简单方法
with open('test.json', mode='rt', encoding='utf-8') as f:
l = json.load(f)
print(l, type(l))
- 强调
- 针对用途一的特定格式:可以是一种专业的格式=》pickle只有python有
- 针对用途二的特定格式:应该是一种通用, 能够被所有语言识别的格式=》json
七、shelvs模块
import pickle
dic = {'name': 'alvin', 'age': 23, 'sex': 'male'}
# 序列化
res = pickle.dumps(dic)
print(res, type(res))
# 反序列化
s = pickle.loads(res)
print(s, type(s))
八、xml模块和shelve
- xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。
xml的格式如下,就是通过<>节点来区别数据结构的:
<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
九、configparser模块
- conf.init, 或者conf.cfg
# 注释
; 注释
[sections1]
k1=v1
is_admin=true
salary=31
age=18
[sections2]
k1 = v1
- common/conf.py
# 加载某种格式的配置文件
import configparser
conf = configparser.ConfigParser()
conf.read('conf.cfg')
# 获取所有的section
print(conf.sections())
# 获取某一section下的所有配置项options
print(conf.options('sections1'))
# 获取items
print(conf.items('sections1'))
# 获取某一特定的值, 结果为字符串
res = conf.get('sections1', 'k1')
print(res, type(res))
# 获取某一特定的值, 结果为int
res = conf.getint('sections1', 'age')
print(res, type(res))
# 获取某一特定的值, 结果为boolean
res = conf.getboolean('sections1', 'is_admin')
print(res, type(res))
# 获取某一特定值的, 结果为float
res = conf.getfloat('sections1', 'salary')
print(res, type(res))
十、hashlib模块
-
什么叫hash:hash是一种算法
- (3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的内容,经过运算得到一串hash值
-
hash值的特点是:
- Ⅰ 只要传入的内容一样,得到的hash值必然一样=====>要用明文传输密码文件完整性校验
- Ⅱ不能由hash值返解成内容=======> 把密码做成hash值,不应该在网络传输明文密码
- Ⅲ 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的
-
hash的用途
- 用途一: 特点Ⅱ用于密码的密文传输与验证
- 用途二: 特点Ⅰ、Ⅲ用于文件完整性校验
- 基本使用
import hashlib
# 如何用, 验证只要传入的内容一样,得到的hash值必然一样=
m = hashlib.md5()
m.update('hello'.encode('utf-8'))
m.update('zpp'.encode('utf-8'))
res = m.hexdigest()
print(res)
m1 = hashlib.md5('he'.encode('utf-8'))
m1.update('llo'.encode('utf-8'))
m1.update('zpp'.encode('utf-8'))
res = m1.hexdigest()
print(res)
- 校验文件
# 校验文件的时候
# 方法一: 不推荐,如果文件过大
m.update('所有文件的内容')
m.hexdigest()
# 方法二: 推荐, 但是会占用资源, 所以随机取出一些行作为验证
f = open('a.txt', mode='rb')
f.seek() # 设置随机种子
f.read(2000)
m.update('一行文件')
m.update('一行文件')
m.update('一行文件')
m.update('一行文件')
m.hexdigest()
- 撞库获取明文密码
# 假设截获一个hash格式的密码passhash = 7635fbcd0d249f02f5558bf0eb241c04
passhash = '7635fbcd0d249f02f5558bf0eb241c04'
# 制作密码字段、一般网上有
passwds = ['zpp1234', 'zpp4567', 'z1234pp', 'zpp456']
dic = dict()
for p in passwds:
res = hashlib.md5(p.encode('utf-8'))
dic[p] = res.hexdigest()
# 模拟撞库得到密码
for k, v in dic.items():
if v == passhash:
print('撞库成功, 明文密码是:{0}'.format(k))
break
- 密码加盐,提升撞库成本
# 真正的密码是:zpp1234
# 在特定位置加上毫无相关的东西
# 加盐后的密码是: z我pp爱1234你
十一、suprocess模块
# 查看系统命令
import subprocess
# 正确
# obj = subprocess.Popen('dir', shell=True,
# stdout=subprocess.PIPE, # 管道符, 输出到管道里
# stderr=subprocess.PIPE # 如果有错误, 输出到另外一个管道里
# )
# 错误
obj = subprocess.Popen('ls /root', shell=True,
stdout=subprocess.PIPE, # 管道符, 输出到管道里
stderr=subprocess.PIPE # 如果有错误, 输出到另外一个管道里
)
print(obj)
# 打印正确输出的管道
print(obj.stdout.read().decode('gbk'))
# 打印错误输出的管道
print(obj.stderr.read().decode('gbk'))
十二、logging模块
- 基础日志的使用
# 日志模块的使用 logging
# start.py一般会放置在整个项目下
import logging
# 一:日志配置
logging.basicConfig(
# 1、日志输出位置:1、终端 2、文件
filename='../ATM/access.log', # 不指定,默认打印到终端
# 2、日志格式, 时间, 名字, 等级
format='%(asctime)s - %(name)s : %(levelname)s -%(module)s: %(message)s',
# 3、时间格式
datefmt='%Y-%m-%d %H:%M:%S %p',
# 4、日志级别
# critical => 50
# error => 40
# warning => 30
# info => 20
# debug => 10
level=30,
)
# 二:输出日志
logging.debug('调试debug') # 10
logging.info('消息info') # 20
logging.warning('警告warn') # 30
logging.error('错误error') # 40
logging.critical('严重critical') # 50
- settings模块
import os
import logging.config
# 1. 日志字典解释
# 可在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
# filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
# filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
# format:指定handler使用的日志显示格式。
# datefmt:指定日期时间格式。
# level:设置rootlogger(后边会讲解具体概念)的日志级别
# stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
#
# format参数中可能用到的格式化串:
# %(name)s Logger的名字
# %(levelno)s 数字形式的日志级别
# %(levelname)s 文本形式的日志级别
# %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
# %(filename)s 调用日志输出函数的模块的文件名
# %(module)s 调用日志输出函数的模块名
# %(funcName)s 调用日志输出函数的函数名
# %(lineno)d 调用日志输出函数的语句所在的代码行
# %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
# %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
# %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
# %(thread)d 线程ID。可能没有
# %(threadName)s 线程名。可能没有
# %(process)d 进程ID。可能没有
# %(message)s用户输出的消息
# 2. 定义三种日志输出格式 开始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
# 定义日志输出格式 结束
logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录
logfile_name = 'all2.log' # log文件名
# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
os.mkdir(logfile_dir)
# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)
# 3. log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': { # 多个日志的格式
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
}
},
'filters': {},
'handlers': { # 控制,操控, 日志的接收者
# 打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
# 打印到文件的日志, 收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024 * 1024 * 5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': { # 产生不同的日志, 日志的产生者
# logging.getLogger(__name__)拿到的logger配置
'll': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # 两层关卡
'propagate': True, # 向上(更高level的logger)传递
},
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # 两层关卡
'propagate': True, # 向上(更高level的logger)传递
}
},
}
def load_my_logging_cfg():
logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
logger = logging.getLogger(__name__) # 生成一个log实例
logger.info('It works!') # 记录该文件的运行状态
if __name__ == '__main__':
load_my_logging_cfg()
- start.py
# 接下来要做的是: 拿到日志的生产者即loggers来产生日志
# 拿到ll
# 但是需要先导入日志配置字典LOGGING_DIC
from conf import settings
import logging
from logging import config, getLogger
config.dictConfig(settings.LOGGING_DIC)
logger1 = getLogger('ll') # 就是name, 如果相同的配置,找不到这个名字 默认从''查找
logger1.info('这是一条info日志')
logger2 = getLogger('终端日志') # 就是name, 如果相同的配置,找不到这个名字 默认从''查找
logger1.info('这是一条info日志, 终端日志')
- 补充
- 日志名的命名
- 日志名是区别日志业务属性的一种非常重要的标识
- 日志轮转
- 就是settings的default,控制某个日志文件的大小, 超过以后自动新建一个日志, 将日志分开, 不存到一个文件中
十三、re模块
十四、猴子补丁
# 用自己的代码替换别
import os
import sys
import json
import ujson # 速度更快
# 条件, 很多py文件中已经用了这个模块,如何打补丁, 写在哪里可以更改每一个模块的, 临时打一个补丁
# 在入口文件, start.py处
def monkey_patch_json():
json.__name__ = 'ujson'
json.dumps = ujson.dumps
json.loads = ujson.loads
monkey_patch_json()
# json.dumps() = 用更好的dumps功能
# json.loads() = 用更好的loads功能
if __name__ == '__main__':
monkey_patch_json()
print(monkey_patch_json.__name__)
print(json.__name__)
pass
相关连接(笔记来自于视频课程的归类整理):
[1]: https://www.bilibili.com/video/BV1QE41147hU?p=17
[2]: https://www.zhihu.com/column/c_1189883314197168128
[3]: https://www.cnblogs.com/linhaifeng/articles/6384466.html