20反射、md5加密、以及日志模块logging(复习)
1、反射
关键字:
getattr 根据字符串的形式,去对象中找该成员
hasattr 根据字符串的形式,判断对象中是否有该成员
setattr 根据字符串的形式,去对象动态设置一个成员(内存)
delattr 根据字符串的形式,去判断对象动态的设置一个成员(内存)
简单例子:
1、在handler文件中定义五个函数及一个数字
def f1(): print("F1") def f2(): print("F2") def f3(): print("F3") def f4(): print("F4") def f5(): print("F5") f0 = 9
2、然后新建一个run文件。根据input的数字去调对应的函数
from types import FunctionType import handler while True: print(""" 系统支持的函数有: 1.f1 2.f2 3.f3 4.f4 5.f5 6.f6 """) val = input("请输入要执行的函数:") if hasattr(handler, val): # 判断是否输入正常 func_or_val = getattr(handler, val) # 根据字符串为参数,去模块中寻找与之同名的成员 if isinstance(func_or_val, FunctionType): func_or_val() else: print(func_or_val) else: print('不存在输入的属性名') # 总结。根据字符串为参数(第二个参数),去对象(第一个参数)中寻找与之同名的成员
当数据量比较庞大时,不可能写一堆的判断,此时反射就显得尤为重要。
总结:
什么是反射:以字符串为参数(第二个参数),去对象中(第一个参数)找与之同名的成员(一句话概括:通过字符串的形式操作对象相关的属性)
2、md5加密
在python中md5加密依赖于hashlib模块
平常的md5加密,很容易被撞库破解。这时候需要加盐。
简单例子如下:
import hashlib SALT = b'asdasd' def md5(pwd): obj = hashlib.md5(SALT) # 加盐 SALT obj.update(pwd.encode('utf-8')) # 获取密文 v = obj.hexdigest() return v
# 由于md5是不可逆的,所以md5的解密。是拿已加密的数据和明文加密的数据进行比对,从而得出结论。
3、日志。
日志用到的是python的logging模块。简单例子如下:
import logging logger = logging.basicConfig(filename='xx.text', format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=30) def func(): try: a = a + 1 except Exception as e: logging.error(e) func()
打印结果如下:
2019-07-23 11:11:37 - root - ERROR - 日志: local variable 'a' referenced before assignment
此时,我们是使用的原生的logging,局限性太多,如所有的日志都会存在一个文件。然后我们重新写一个。
# coding:utf-8 import logging, time import os # log_path是存放日志的路径 cur_path = os.path.dirname(os.path.realpath(__file__)) log_path = os.path.join(os.path.dirname(cur_path), 'logs') # 如果不存在这个logs文件夹,就自动创建一个 if not os.path.exists(log_path):os.mkdir(log_path) class Log(): def __init__(self): # 文件的命名 self.logname = os.path.join(log_path, '%s.log'%time.strftime('%Y_%m_%d')) self.logger = logging.getLogger() self.logger.setLevel(logging.DEBUG) # 日志输出格式 self.formatter = logging.Formatter('[%(asctime)s] - %(filename)s] - %(levelname)s: %(message)s') def __console(self, level, message): # 创建一个FileHandler,用于写到本地 # fh = logging.FileHandler(self.logname, 'a') # 追加模式 这个是python2的 fh = logging.FileHandler(self.logname, 'a', encoding='utf-8') # 这个是python3的 fh.setLevel(logging.DEBUG) fh.setFormatter(self.formatter) self.logger.addHandler(fh) # 创建一个StreamHandler,用于输出到控制台 ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) ch.setFormatter(self.formatter) self.logger.addHandler(ch) if level == 'info': self.logger.info(message) elif level == 'debug': self.logger.debug(message) elif level == 'warning': self.logger.warning(message) elif level == 'error': self.logger.error(message) # 这两行代码是为了避免日志输出重复问题 self.logger.removeHandler(ch) self.logger.removeHandler(fh) # 关闭打开的文件 fh.close() def debug(self, message): self.__console('debug', message) def info(self, message): self.__console('info', message) def warning(self, message): self.__console('warning', message) def error(self, message): self.__console('error', message)
然后使用的时候配合traceback模块(需先导入)。
def func(self): try: a = a + 1 except Exception as e: # 获取当前错误的堆栈信息 msg = traceback.format_exc() self.log.error(msg) return '500'
日志结果为:
此时,一个完整的日志处理模块就完成了(后续还可以按照等级,分不同的文件),不过后面的开发框架都已经有很完善的了。这里就不过多赘述了。