logging模块
日志就是记录一些信息,方便查询或者辅助开发
记录文件,显示屏幕
低配日志, 只能写入文件或者屏幕输出
屏幕输出
import logging logging.debug('调试模式') #默认只输出warning以上信息, logging.info('正常运行') logging.warning('警告') logging.error('错误') logging.critical('系统崩溃') WARNING:root:警告 ERROR:root:错误 CRITICAL:root:系统崩溃
写入文件
import logging logging.basicConfig( level=logging.DEBUG, #level=10, # 显示的级别 format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', # 显示格式 datefmt='%Y %m %d', # 日期 filename='a.log', # 默认是a模式, 就是使用的gbk 编码。 # filemode='w' #一般只用追加写入,不用写入 因此不用改写模式。 ) logging.debug('调试模式') # 等于10 logging.info('正常运行') # 等于20 logging.warning('警告') # 等于30 logging.error('错误') # 等于40 logging.critical('系统崩溃') # 等于50
标配日志,可屏幕输出也可记录日志
import logging # 创建logging对象 log = logging.getLogger() # 创建文件对象 f1 = logging.FileHandler('file1.log', encoding='utf-8') f2 = logging.FileHandler('file2.log', encoding='utf-8') #创建屏幕对象 sh = logging.StreamHandler() # 日志格式设置 format1 = logging.Formatter( fmt='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', # 显示格式 datefmt='%Y-%m-%d %H:%M:%S',) #显示时间设置 format2 = logging.Formatter( fmt='%(asctime)s %(filename)s %(levelname)s ', # 显示格式 datefmt='%Y-%m-%d %H:%M:%S',) #显示时间设置 format3 = logging.Formatter( fmt='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', # 显示格式 datefmt='%Y-%m-%d %H:%M:%S',) #显示时间设置 # 给创建的输出对象绑定格式 f1.setFormatter(format1) f2.setFormatter(format2) sh.setFormatter(format3) #给log对象添加输出对象 log.addHandler(f1) log.addHandler(f2) log.addHandler(sh) #设置级别 log.setLevel(20) sh.setLevel(30) f1.setLevel(30) f2.setLevel(40) logging.debug('调试模式') logging.info('正常运行') logging.warning('警告') logging.error('错误') logging.critical('系统崩溃')
高配日志
通过导入文件(字典的方式)写日志,Django
import os import logging.config # 定义日志的输出的格式 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' # 找到当前目录绝对路径 __file__ logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录的绝对路径 logfile_name = '高配版.log' # log文件名 # # 如果不存在定义的日志目录就创建一个 # if not os.path.isdir(logfile_dir): # os.mkdir(logfile_dir) # log文件的全路径 logfile_path = os.path.join(logfile_dir, logfile_name) # log配置字典 # 第一层键值对的键固定的关键字不能改变。 LOGGING_DIC = { 'version': 1, # 版本 'disable_existing-loggers': False, # 禁用现有的log日志 'formatters': { # 定义三种不同的日志格式 'standard': { # 格式1 'format': standard_format }, 'simple': { # 格式2 'format': simple_format }, 'id_simple_format': { # 格式3 'format': id_simple_format } }, 'filters': {}, # 过滤 'handlers': { 'console': { # 打印到终端的日志 'level': 'DEBUG', # 日志级别 'class': 'logging.StreamHandler', # 类:打印到屏幕 'formatter': 'simple' # 日志的格式 }, 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', # 日志的格式 'filename': logfile_path, # 日志文件的绝对路径 'maxBytes': 1024*1024*5, # 日志大小5M,以bytes 'backupCount': 5, # 最多只有5个文件 'encoding': 'utf-8', }, }, 'loggers': { '': { 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 }, }, } logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置 # # logging.config # 将你写好的logging 字典 在导入logging.config后,传到logging模块中 logger = logging.getLogger() # 生成一个log实例 通过字典自己设置的个性化的log对象 logger.info('正常运行状态') # 记录该文件的运行状态
hashlib模块
1.加密的类型必须是str
2.无论这个str多长,加密之后都是转化成等长度的数字.
3.无论在任何机器上,
不同的字符串加密后一定不同
import hashlib ret = hashlib.md5() #定义一个ret的对象 ret.update('wk'.encode('utf-8')) #将字符串'wk'转为bytes 加密 print(ret.hexdigest()) #查看转换后的密文 5d2bf8e6622cb88ca16a745dcf8153a0
用途:
1,对密码进行加密
md5加密
a.普通的md5加密
import hashlib def encryption(passwd): #加密函数 ret = hashlib.md5() ret.update(passwd.encode('utf-8')) return ret.hexdigest() def register(): user = input('>>>') passwd = input('>>>') passwd = encryption(passwd) with open('ku', encoding='utf-8', mode='a') as f1: f1.write('{}|{}'.format(user, passwd)) register()
用户注册完登录时,将登陆的密码再次加密然后与存储的进行对比
b,加盐
import hashlib def encryption(passwd): ret = hashlib.md5('加盐'.encode('utf-8')) #在别人设置的密码前再加一串固定的字符,使md5不容易破译,但是如果别人知道你的盐是什么还是可以破译 ret.update(passwd.encode('utf-8')) return ret.hexdigest() def register(): user = input('>>>') passwd = input('>>>') passwd = encryption(passwd) with open('ku', encoding='utf-8', mode='a') as f1: f1.write('{}|{}'.format(user, passwd)) register()
c.动态加盐
import hashlib def encryption(user, passwd): ret = hashlib.md5(user[::2].encode('utf-8')) #加的盐为用户名字符的奇数字符 ret.update(passwd.encode('utf-8')) return ret.hexdigest() def register(): user = input('>>>') passwd = input('>>>') passwd = encryption(user,passwd) with open('ku', encoding='utf-8', mode='a') as f1: f1.write('{}|{}'.format(user, passwd)) register()
sha加密
import hashlib def encryption(user, passwd): ret = hashlib.sha1(user[::2].encode('utf-8')) #与md5用法一样,把md5改为sha1
ret.update(passwd.encode('utf-8')) return ret.hexdigest() def register(): user = input('>>>') passwd = input('>>>') passwd = encryption(user,passwd) with open('ku', encoding='utf-8', mode='a') as f1: f1.write('{}|{}'.format(user, passwd)) register()
哈希的加密方法有很多,尾数越高,加密方法越复杂,效率越低
2.文件的校验
校验文件就是把文件的内容生成MD5值,把MD5值对比校验
校验文件
import hashlib def file_hashlib(file): ret = hashlib.md5() with open(file,mode='rb') as f1: ret.update(f1) return ret.hexdigest() file_hashlib('文件')
校验可以累加
import hashlib s1 = '蹦沙卡拉卡' #一个字符串一次性读取和分次读取其生成的MD5值一样(必须是相同字符串) ret = hashlib.md5() ret.update(s1.encode('utf-8')) print(ret.hexdigest()) ret = hashlib.md5() ret.update('蹦'.encode('utf-8')) ret.update('沙'.encode('utf-8')) ret.update('卡'.encode('utf-8')) ret.update('拉'.encode('utf-8')) ret.update('卡'.encode('utf-8')) print(ret.hexdigest()) 5f46742e84df43713d132852859aa3bb 5f46742e84df43713d132852859aa3bb
对于大文件每次读取一行,按行累加校验
import hashlib def file_hashlib(file): ret = hashlib.md5() with open(file,mode='rb') as f1: for i in f1: # 循环每行读取 ret.update(i) return ret.hexdigest() file_hashlib('文件')
异常处理
异常发生后下边的代码就不再执行了
单支情况 try except
name #单有一个变量名运行 Traceback (most recent call last): #报错 File "F:/python24期/python/123.py", line 1, in <module> name NameError: name 'name' is not defined #报错 NameError
try--except: 尝试着运行try里面的代码,出现错误,按照错误类型去寻找相应的except,找到执行except里的代码,然后程序继续运转.
try: #代码可以运行并且不报错 print(555) name #出现错误即跳转到except,不在往下执行 print(666) except NameError: #定义错误类型 print('name name is not defined') print(777) 555 #错输出结果可见,try里的 错误代码下的代码不执行, 遇到错误后看except是否有指定错误,如果有,执行except里的代码, name name is not defined 777
上述方法只能锁定一个错误,如果错误没有在except里,则程序还会报错
try: print(555) l1 = [1, 2, 3] print(l1[10]) #打印列表的第10个参数,但是列表里只有2个参数 此时报IndexError错误 print(666) except NameError: #except里没有定义IndexError错误,因此程序执行到print(l1[10])还是会报错并终止程序 print('name name is not defined') print(777) Traceback (most recent call last): 555 File "F:/python24期/python/123.py", line 4, in <module> print(l1[10]) IndexError: list index out of range
多支情况 try except except except ......
try: print(555) name l1 = [1, 2, 3] print(l1[10]) print(666) dic = {'name': 'alex'} print(dic['age']) except NameError: #定义多个except,但是还是try里的代码,遇到错误即停止往下执行 print('name name is not defined') except IndexError: print('索引超出范围....') except KeyError: print('没有此key...') print(777) 555 name name is not defined 777
万能处理 Exception
如果你对错误原因不关心,只是想不让其报错,那么程序中你就用万能处理.
如果你对错误原因需要进行不同分流或者程序处理,那么就需要多分支.
try: print(555) name l1 = [1, 2, 3] print(l1[10]) print(666) dic = {'name': 'alex'} print(dic['age']) except Exception as e: #Exception可以接收所有错误, as e 把错误结果赋值给e print(e) print(777) 555 name 'name' is not defined 777
多分支加万能处理
try: print(555) name l1 = [1, 2, 3] print(l1[10]) print(666) dic = {'name': 'alex'} print(dic['age']) except NameError: #定义多个except, print('name name is not defined') except IndexError: print('索引超出范围....') except KeyError: print('没有此key...') except Exception as e: #前边分流接收,最后以Exception 收尾 print(e) print(777)
try except else
try: print(555) name except NameError: print('name name is not defined') else: #如果try里报错并且执行except,则代码往下走不执行else print(999) print(777) 555 #输出结果没有执行else里的代码 name name is not defined 777
try: print(555) name = 123 except NameError: #如果try里的代码没有报错,并且没有执行except,则执行else里的代码 print('name name is not defined') else: print(999) print(777) 555 999 #此处执行了else里的代码 777
try finally
finaly 不管对与错都执行finally 但是代码不会继续往下走,
try: name = 123 finally: print(777) try: li = [1,2,3] print(li[10]) finally: print(666) print(888) #print(888)没有执行 Traceback (most recent call last): 777 #不管对错finally内的代码都执行了 666 File "F:/python24期/python/123.py", line 7, in <module> print(li[10]) IndexError: list index out of range
常作用于关闭文件,关闭连接,关闭数据库等等
f1 = open('a.log', encoding='utf-8') f1.read() ''' 各种对文件操作的代码,但是可能会出错,出错之后,你的文件句柄无法关闭。 ''' f1.close()
# 解决方案: try: f1 = open('a.log', encoding='gbk') f1.read() f1.write('sfdsf') ''' 各种对文件操作的代码,但是可能会出错,出错之后,你的文件句柄无法关闭。 ''' finally: print(666) f1.close()
try findally也可以作用于函数
def aa(x): try: c = x + 1 return c finally: #finally作用于函数先执行finally再执行return print(666) print(aa(1)) 666 #先执行的findlly 2 #再执行的c=2
try except finally
try: name = 123 finally: print(777) try: li = [1,2,3] print(li[10]) except Exception: pass finally: print(666) print(888) 777 666 888
自定义异常处理
python提供了大部分异常,但是不是所有,比如 大的框架的手机连接问题,网络引发的代码问题等等.
Exception 也处理不了.
class PhoneConnectionError(BaseException): #定义一个类,继承BaseException 类 pass raise PhoneConnectionError('错误类型') #raise报一个指定的错误,此错误必须定义class PhoneConnectionError(BaseException):才能出现 Traceback (most recent call last): File "F:/python24期/python/123.py", line 5, in <module> raise PhoneConnectionError('错误类型') __main__.PhoneConnectionError: 错误类型 #PhoneConnectionError的错误
要想让except能够找到自定义的错误类型,需要自定义一个错误类并且继承BaseException累
class PhoneConnectionError(BaseException): #如果出现python解决不了的错误类型,就定义一个错误类,让这个类继承BaseException pass try: raise PhoneConnectionError('错误类型') except PhoneConnectionError: print('手机连接出现了问题') 手机连接出现了问题
assert 断言 只要条件不成立就报错
assert 1 == 2 #源码中经常遇到 只要条件不成立,我就抛出错误
Traceback (most recent call last): File "F:/python24期/python/123.py", line 1, in <module> assert 1 == 2 AssertionError
datetime模块
获取当前时间
import datetime now_time = datetime.datetime.now() print(now_time)
2019-01-10 19:49:42.388032
获取3周之后和3周之前的当前时间
import datetime print(datetime.datetime.now()) print(datetime.datetime.now()+datetime.timedelta(weeks=3)) #3周之后的时间 print(datetime.datetime.now()+datetime.timedelta(weeks=-3)) #3周之前的时间 2019-01-10 19:55:01.222595 2019-01-31 19:55:01.222595 2018-12-20 19:55:01.222595
获取其他时间
import datetime print(datetime.datetime.now()) print(datetime.datetime.now()+datetime.timedelta(days=3)) #3天后 print(datetime.datetime.now()+datetime.timedelta(days=-3)) #3天前 print(datetime.datetime.now()+datetime.timedelta(hours=3)) #3小时后 print(datetime.datetime.now()+datetime.timedelta(hours=-3)) #3小时前 print(datetime.datetime.now()+datetime.timedelta(minutes=3)) #3分钟后 print(datetime.datetime.now()+datetime.timedelta(minutes=-3)) #3分钟前 print(datetime.datetime.now()+datetime.timedelta(seconds=3)) #3秒后 print(datetime.datetime.now()+datetime.timedelta(seconds=-3)) #3秒前 2019-01-10 19:59:35.137924 2019-01-13 19:59:35.137924 2019-01-07 19:59:35.137924 2019-01-10 22:59:35.137924 2019-01-10 16:59:35.137924 2019-01-10 20:02:35.137924 2019-01-10 19:56:35.137924 2019-01-10 19:59:38.137924 2019-01-10 19:59:32.137924
可直接调整到年月日时分秒
import datetime current_time = datetime.datetime.now() print(current_time.replace(year=1977)) # 直接调整到1977年 print(current_time.replace(month=1)) # 直接调整到1月份 print(current_time.replace(year=1989,month=4,day=25)) # 1989-04-25 18:49:05.898601 1977-01-10 20:03:57.756185 2019-01-10 20:03:57.756185 1989-04-25 20:03:57.756185
将时间戳转化成时间
import datetime print(datetime.date.fromtimestamp(1232132131)) 2009-01-17
shutil模块
对普通文件操作
高级的 文件、文件夹、压缩包 处理模块
shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中
import shutil shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
shutil.copyfile(src, dst)
拷贝文件
shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在
shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变
shutil.copymode('f1.log', 'f2.log') #目标文件必须存在
shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copystat('f1.log', 'f2.log') #目标文件必须存在
shutil.copy(src, dst)
拷贝文件和权限
import shutil shutil.copy('f1.log', 'f2.log')
shutil.copy2(src, dst)
拷贝文件和状态信息
import shutil shutil.copy2('f1.log', 'f2.log')
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹
import shutil shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
shutil.rmtree(path[, ignore_errors[, onerror]])递归的去删除文件
import shutil shutil.rmtree('folder1')
shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。
shutil.move('folder1', 'folder3')
打包压缩
shutil.make_archive(base_name, format,...)
创建压缩包并返回文件路径,例如:zip、tar
创建压缩包并返回文件路径,例如:zip、tar
- base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如 data_bak =>保存至当前路径
如:/tmp/data_bak =>保存至/tmp/ - format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
- root_dir: 要压缩的文件夹路径(默认当前目录)
- owner: 用户,默认当前用户
- group: 组,默认当前组
- logger: 用于记录日志,通常是logging.Logger对象
#将 /data 下的文件打包放置当前程序目录 import shutil ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data') #将 /data下的文件打包放置 /tmp/目录 import shutil ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:
import zipfile # 压缩 z = zipfile.ZipFile('laxi.zip', 'w') z.write('a.log') z.write('data.data') z.close() # 解压 z = zipfile.ZipFile('laxi.zip', 'r') z.extractall(path='.') z.close() zipfile压缩解压缩 import tarfile # 压缩 >>> t=tarfile.open('/tmp/egon.tar','w') >>> t.add('/test1/a.py',arcname='a.bak') >>> t.add('/test1/b.py',arcname='b.bak') >>> t.close() # 解压 >>> t=tarfile.open('/tmp/egon.tar','r') >>> t.extractall('/egon') >>> t.close() tarfile压缩解压缩
xml模块(了解)
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> xml数据 xml文件
# 增删改查 # 在进行操作之前,都应该进行这两步: # import xml.etree.ElementTree as ET # tree = ET.parse('a.xml') # 形成树形结构 # root = tree.getroot() # 得到树的根系 # print(root) # 循环打印: # for i in root: # print(i) # <Element 'country' at 0x00000196B51191D8> # <Element 'country' at 0x00000196B5124B88> # <Element 'country' at 0x00000196B5124D18> # 所有的增删改查都是基于这个root根系去操作 # 查: # 1,全文搜索 year 将所有的year标签全部找 # print(root.iter('year')) # print([i for i in root.iter('year')]) # 2,只找第一个,找到就返回 # print(root.find('country')) # 3,在root的子节点找,找所有的 # print(root.findall('country')) # 练习 # 找到标签也可以找到标签相应的内容:tag,attrib,text # 1,找所有的rank标签,以及 attrib 和 text (这里利用列表推导式比较方便) # print([i for i in root.iter('rank')]) # [<Element 'rank' at 0x000001367D0D49F8>, <Element 'rank' at 0x000001367D0D4BD8>, <Element 'rank' at 0x000001367D0D4D68>] # print([i.attrib for i in root.iter('rank')]) # [{'updated': 'yes'}, {'updated': 'yes'}, {'updated': 'yes'}] # print([i.text for i in root.iter('rank')]) # ['2', '5', '69'] # 2,找到第二个country的 neighbor标签以及他的属性 # print([tag for tag in root.findall('country')][1].find('neighbor').attrib) # {'direction': 'N', 'name': 'Malaysia'} # 增 append # import xml.etree.ElementTree as ET # tree = ET.parse('a.xml') # 形成树形结构 # root = tree.getroot() # 得到树的根系 # 给 year 大于2010年的所有标签下面添加一个month标签,属性为name:month 内容为30days # for country in root.findall('country'): # for year in country.findall('year'): # if int(year.text) > 2010: # month = ET.Element('month') # month.text = '30days' # month.attrib = {'name': 'month'} # country.append(month) # tree.write('b.xml') #改 # import xml.etree.ElementTree as ET # tree = ET.parse('a.xml') # 形成树形结构 # root = tree.getroot() # 得到树的根系 # 对所有的year属性以及值进行修改 # for node in root.iter('year'): # new_year=int(node.text)+1 # node.text=str(new_year) # node.set('updated','yes') # node.set('version','1.0') # tree.write('test.xml') # 删 # import xml.etree.ElementTree as ET # tree = ET.parse('a.xml') # 形成树形结构 # root = tree.getroot() # 得到树的根系 # # # 将 rank值大于50的country标签删除 # for country in root.findall('country'): # rank = int(country.find('rank').text) # if rank > 50: # root.remove(country) # # tree.write('output.xml') 对xml的增删改查简单操作
import xml.etree.ElementTree as ET new_xml = ET.Element("namelist") name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"}) age = ET.SubElement(name,"age",attrib={"checked":"no"}) sex = ET.SubElement(name,"sex") sex.text = '33' name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"}) age = ET.SubElement(name2,"age") age.text = '19' et = ET.ElementTree(new_xml) #生成文档对象 et.write("test.xml", encoding="utf-8",xml_declaration=True) ET.dump(new_xml) #打印生成的格式 自己创建xml文档