part5
1.单例模式
无论实例化多少次,永远用的都是第一次实例化出的对象。
class Foo:
pass
# 多例,每实例化一次就创建一个新的对象(即多开一块空间)
obj1 = Foo()
obj2 = Foo()
# 单例,无论实例化多少次都用第一次创建的那个对象。
# ##########多例模式#########
# class Singleton(Object):
# pass
#
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1,obj2)
# # <__main__.Foo object at 0x000002E725678400> <__main__.Foo object at 0x000002E725656640>
############单例模式###########
class Singleton(object):
instance = None
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)
# <__main__.Foo object at 0x0000018774120340> <__main__.Foo object at 0x0000018774120340>
不是最终的形式,以上只是帮助了解。(最终需要加锁)
应用场景:数据库连接和连接池
# 文件连接池
class FileHelper:
instance = None
def __init__(self,path):
self.file_object = open(path,mode="r",encoding="utf-8")
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
obj1 = FileHelper('text5_1.txt')
obj2 = FileHelper('text5_1.txt')
print(obj1.file_object.read(1))
print(obj2.file_object.read(10))
通过模块导入的特性也可以实现单例模式:
# child.py
class Foo:
pass
obj = Foo()
# main.py
import child # 加载child.py后会实例化一个Foo对象并赋值给obj
print(child.obj)
print(child.obj)
# 以上两个对象是公用一块内存的
2.日志(logging模块)
import logging
logging.basicConfig(filename='daylog1.log',level=20)
logging.log(10,'10') # <20不会执行
logging.log(30,'30') # >20会执行
# level一般不会自己去写
# 在logging.ERROR里可以查看到以下信息
# CRITICAL = 50 => 崩溃严重错误
# FATAL = CRITICAL
# ERROR = 40 => 错误
# WARNING = 30 => 警告
# WARN = WARNING
# INFO = 20 => 正常信息
# DEBUG = 10 => 调试
# NOTSET = 0 => 不设置
logging.basicConfig(filename='daylog2.log',level=logging.INFO)
logging.log(10,'10')
logging.debug('10') # 效果同上
logging.log(30,'30') # >20会执行
logging.warn('30') # 效果同上(横线代表将会被移除),所以使用以下的格式
logging.warning('30') # 效果一样
1.快速使用
import logging
# 配置信息(多次配置是无效的,只会执行第一次)
logging.basicConfig(
filename='daylog.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=logging.ERROR
)
logging.error('a1')
# 相关信息参考:https://www.cnblogs.com/wupeiqi/articles/5501365.html
应用场景:对于异常处理捕获到的内容,使用日志模块将其保留到日志文件。
import logging
import requests
logging.basicConfig(
filename='daylog.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=logging.ERROR
)
try:
requests.get('http://www.xxx.com')
except Exception as e:
msg = str(e) # 调用e.__str__方法
logging.error(msg,exc_info=True) # exc_info=True => 会将堆栈信息一起返回
basicConfig的底层(本质):
import logging
# 指定日志文件
file_handler = logging.FileHandler('x1.log', 'a', encoding='utf-8')
# 规定格式要求
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s")
# 将要求赋给指定的日志文件
file_handler.setFormatter(fmt)
# 创建一个写日志的对象
logger = logging.Logger('s1', level=logging.ERROR)
# 告诉该对象上述指定的日志文件规则
logger.addHandler(file_handler)
# 进行日志书写
logger.error('hello world!')
logger.error('你好')
2.一次写入多个文件
# 一次写入多个文件
import logging
file_handler1 = logging.FileHandler('x1.log', 'a', encoding='utf-8')
fmt1 = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s")
file_handler1.setFormatter(fmt1)
file_handler2 = logging.FileHandler('x2.log', 'a', encoding='utf-8')
fmt2 = logging.Formatter(fmt="%(asctime)s : %(message)s")
file_handler1.setFormatter(fmt2)
logger = logging.Logger('s1', level=logging.ERROR)
# 将所有的文件对象都添加给logger对象(这样满足条件的文件可以同时写入)
logger.addHandler(file_handler1)
logger.addHandler(file_handler2)
logger.error('hello world!')
logger.error('你好')
3.推荐日志方式
import logging
file_handler = logging.FileHandler('standard.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('你好')
logging.error('hello world!')
4.日志切割
import logging
import time
from logging import handlers
file_handler = handlers.TimedRotatingFileHandler(filename='log/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,20):
time.sleep(1)
logging.error(str(i))
3.项目目录结构
1.脚本
内置模块在第三方模块上方,模块按名字由短至长排列。
2.单可执行文件
src:业务相关的功能(登陆注册、购买商品等等)
lib:公共的代码、类、库(比如分页代码)
db:存放数据
config:存放配置文件
log:存放日志文件
3.多可执行文件
示例
# student.py
from src.run import start
if __name__ == '__main__':
start()
# settings.py
import os
# 获取到example这个根文件的路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(BASE_DIR)
# 修改日志名字在这里不用去动代码了
LOG_FILE_NAME = "cmdb.log"
LOG_FILENAME = os.path.join(BASE_DIR,'log',LOG_FILE_NAME)
LOG_WHEN = "s"
LOG_INTERVAL = 5
# log.py
# 此处为了方便,一般把日志存放在项目之外(将日志保存路径修改即可)
import os
import logging
from config import settings
from logging import handlers
def get_logger():
# 如果要切割日志也是在该文件中操作
# file_handler = handlers.TimedRotatingFileHandler(filename=LOG_FILE_NAME,
# when=settings.LOG_WHEN,
# interval=settings.LOG_INTERVAL,
# encoding='utf-8')
file_handler = logging.FileHandler(settings.LOG_FILE_NAME, 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
)
return logging
logger = get_logger()
# account.py
from lib.log import logger
def login():
print("登录")
# 捕获异常
try:
int("sad")
except Exception as e:
print("出错!请重新输入")
# import logging
# logging.error(str(e),exc_info=True)
logger.error(str(e),exc_info=1) # 效果同上
def register():
print("注册")
# order.py
def manger():
print("订单")
# run.py
from src import account
from src import order
def start():
print("1.登录;2.注册;3.订单管理")
func_dict = {'1':account.login,'2':account.register,'3':order.manger}
choice = input("请选择:")
func = func_dict.get(choice)
if not func:
print("输入错误")
func()