No.23
内容概要
作业
单例模式
class Foo(object): pass obj1 = Foo() # 实例(对象) obj2 = Foo() # 实例(对象)
日志模块(logging)
程序的目录结构
内容回顾和补充
1.字符串格式化
# 一类
v1 = '我是%s,年龄%s' % ('alex', '18')
print(v1)
v1 = '我是%(n1)s,年龄%(n2)s' % {'n1': 'alex', 'n2': 18}
print(v2)
# 二类
v2 = '我是{name},年龄{age}'.format(name='alex', age=18)
print(v3)
v2 = '我是{name},年龄{age}'.format(**{'name':'alex', 'age': 18})
print(v3)
# 三类
v3 = '我是{0},年龄{1}'.format('alex', 18)
print(v4)
v3 = '我是{0},年龄{1}'.format(*('alex', 18))
print(v4)
2.有序字典
from collections import OrderedDict
info = OrderedDict()
info['k1'] = 123
info['k2'] = 456
print(info.keys())
print(info.values())
print(info.items())
3.作业
# 7.补充代码实现:校园管理系统。
class User(object):
def __init__(self, name, email, age):
self.name = name
self.email = email
self.age = age
def __str__(self):
return self.name
class School(object):
"""学校"""
def __init__(self):
# 员工字典,格式为:{"销售部": [用户对象,用户对象,] }
self.user_dict = {}
def invite(self, department, user_object):
"""
招聘,到用户信息之后,将用户按照指定结构添加到 user_dict结构中。
:param department: 部门名称,字符串类型。
:param user_object: 用户对象,包含用户信息。
:return:
"""
pass
def dimission(self, username, department=None):
"""
离职,讲用户在员工字典中移除。
:param username: 员工姓名
:param department: 部门名称,如果未指定部门名称,则遍历找到所有员工信息,并将在员工字典中移除。
:return:
"""
pass
def run(self):
'''
主程序
:return:
'''
pass
if __name__ == '__main__':
obj = School()
obj.run()
# 8.请编写网站实现如下功能。
'''
需求:
实现 MIDDLEWARE_CLASSES 中的所有类,并约束每个类中必须有process方法。
用户访问时,使用importlib和反射让MIDDLEWARE_CLASSES中的每个类对login、logout、index方法的返回值进行包装,最终让用户看到包装后的结果。
如:
用户访问 : http://127.0.0.1:8000/login/ ,
页面显示: 【csrf】【auth】【session】 登录 【session】 【auth】 【csrf】
用户访问 : http://127.0.0.1:8000/index/ ,
页面显示: 【csrf】【auth】【session】 首页 【session】 【auth】 【csrf】
即:每个类都是对view中方法返回值的内容进行包装。
'''
MIDDLEWARE_CLASSES = [
'utils.session.SessionMiddleware',
'utils.auth.AuthMiddleware',
'utils.csrf.CrsfMiddleware',
]
from wsgiref.simple_server import make_server
class View(object):
def login(self):
return '登陆'
def logout(self):
return '登出'
def index(self):
return '首页'
def func(environ, start_response):
start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
obj = View()
method_name = environ.get('PATH_INFO').strip('/')
if not hasattr(obj, method_name):
return ["123".encode("utf-8"), ]
response = getattr(obj, method_name)()
return [response.encode("utf-8")]
server = make_server('127.0.0.1', 8000, func)
server.serve_forever()
3.1栈和队列
class Stack(object): # 栈:后进先出
pass
class Queue(object): # 队列:先进先出
pass
3.2反射
class Cloud(object):
def upload(self):
pass
def download(self):
pass
def run(self):
'''规定格式
up|C:/xxx/xxx.zip
down|xxx.py
'''
value = input('请用户输入要干什么')
action = value.split('|')[0]
# 最low形式
if action == 'up':
self.upload()
elif: action == 'down':
self.download()
else:
print('输入错误')
# 构造字典(推荐)
method_dict = {'up':self.upload, 'down':self.download}
method = method_dict.get(action)
method()
# 反射
method = getattr(self, action) # 规定用户输入 upload / download
method()
class Foo(object):
def get(self):
pass
obj = Foo()
# if hasattr(obj, 'post') 性能差
# getattr(obj, 'post')
v = getattr(obj, 'post', 666) # 没找到就返回自定义值 666
3.3循环删除元素
class User(object):
def __init__(self, name, age):
self.name = name
self.age = age
info = [User('武沛齐', 19), User('李杰', 18), User('景女神', 17)]
name = input('请输入要删除的用户名:')
for item in range(len(info) - 1, -1, -1):
if name == info[item].name:
del info[item]
for i in info:
print(i.name)
内容详细
1.单例模式
一共有23种设计模式
- 单例模式:无论实例化多少次,永远用的都是第一次实例化创建的对象。
# 多例,每实例化一次就创建一个新的对象。
class Foo(object):
pass
obj1 = Foo()
obj2 = Foo()
# 单例,无论实例化多少次,都用第一次创建的对象。
class Foo(object):
instance = None
def __new__(cls, *args, **kwargs):
# if Foo.instance:
# return Foo.instance
# Foo.instance = object.__new__(cls)
# return Foo.instance
if not Foo.instance:
Foo.instance = object.__new__(cls)
return Foo.instance
obj1 = Foo()
obj2 = Foo()
单例模式标准
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()
# 不是最终,未来要加锁。
文件的连接池
class FileHelper(object):
instance = None
def __init__(self, path):
self.file = 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('test.txt')
data1 = obj1.file.read(1)
obj2 = FileHelper('test.txt')
data2 = obj2.file.read(2)
2.模块导入
注意事项
''' 注意: 1.模块中全局作用域的执行代码会加载到运行主文件的内存中。 2.非执行代码会单独分配到另一个内存,主文件要调用时必须用模块.对象(广义)的方式执行。 ''' # module.py print(666) a = 888
# 主文件 import module print(a) # 无法获取模块中的值,必须通过module.a的方式获取。 结果:会先打印666,然后报错。
默认多次导入不会重新加载
# module.py print(123) # other_module.py import module
# 主文件 直接重复加载 import module # 第一次导入会加载模块中所有内容 import module # 由于已经加载过了就不会再加载(无论直接或间接) print(456) 间接重复加载 import module import other_module print(456)
import importlib import module importlib.reload(module) # 主动强制重新加载
通过模块导入的特性也可以实现单例模式
# module.py class Foo(object): pass obj = Foo()
# 主文件 import module # 加载module.py,加载最后会实例化一个Foo对象并赋值给obj print(module.obj)
3.日志模块(logging)
- 总结
- 基本应用
- 处理本质:Logger / FileHandler / Formatter
- 推荐方式
import logging file_handler = logging.FileHandler(filename='log_paper.log', mode='a', encoding='utf-8',) logging.basicConfig( handlers = [file_handler], format = '%(asctime)s - %(levelname)s - %(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level = logging.ERROR ) logging.error('你好')
- 推荐方式 + 日志分割
import time import logging from logging import handlers # file_handler = logging.FileHandler(filename='log_paper.log', mode='a', encoding='utf-8',) file_handler = handlers.TimedRotatingFileHandler(filename='log_paper', when='s', interval=5, encoding='utf-8') logging.basicConfig( handlers=[file_handler], format='%(asctime)s - %(levelname)s - %(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level=logging.ERROR ) for i in range(1,100000): time.sleep(1) logging.error(str(i))
3.1快速使用
# 写入信息默认按照操作系统编码,不同操作系统可能会导致日志文件出现乱码。
import logging
logging.basicConfig(
filename = 'cmdb.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('alex')
特殊情况:
import logging
# 只有第一次配置有效
logging.basicConfig(
filename = 'cmdb1.log',
format = '%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s', # 占位符名字官方写死,不能修改否则会报错。
datefmt = '%Y-%m-%d %H:%M:%S %p',
level = logging.ERROR
)
# 无效
logging.basicConfig(
filename = 'cmdb2.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('alex')
应用场景:对于异常处理捕获到的内容,使用日志模块将其保留到日志文件。
import requests
import logging
logging.basicConfig(
filename = 'log_paper.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.google.com')
except Exception as e:
msg = str(e) # 内部会调用e.__str__方法
logging.error(msg, exc_info=True) # 加入参数会把堆栈信息写入日志
3.2内部本质
import logging
logging.basicConfig(
filename = 'cmdb.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('alex')
basicConfig内部做了下面的事情
import logging
# 创建FileHandler对象
# 往哪写:把错误信息写到哪个日志文件,以哪种模式和编码写入?
file_handler = logging.FileHandler('1.log','a',encoding='utf-8')
# 创建Formatter对象
# 怎么写:错误信息是否需要用指定格式写入日志?
fmt = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s')
# 把Formatter对象添加到FileHandler对象中
# 哪个日志文件需要用指定格式写入错误信息
file_handler.setFormatter(fmt)
'''上面三步表示把错误信息按照指定格式写入到指定日志文件'''
# 谁来写
logger = logging.Logger('随便写个Logger对象名',level=logging.ERROR)
logger.addHandler(file_handler)
logger.error('你好')
往不同日志文件按不同格式写入错误信息
import logging
# 配置日志文件1
file_handler1 = logging.FileHandler('1.log','a',encoding='utf-8')
fmt1 = logging.Formatter(fmt='%(asctime)s - %(levelname)s - %(module)s: %(message)s')
file_handler1.setFormatter(fmt1)
# 配置日志文件2
file_handler2 = logging.FileHandler('2.log','a',encoding='utf-8')
fmt2 = logging.Formatter(fmt='%(asctime)s: %(message)s')
file_handler2.setFormatter(fmt2)
# 按不同格式写入不同文件
logger = logging.Logger('往不同地方按不同格式写入错误信息',level=logging.ERROR)
logger.addHandler(file_handler1)
logger.addHandler(file_handler2)
logger.error('你好')
推荐日志写法
import logging
file_handler = logging.FileHandler(filename='log_paper.log', mode='a', encoding='utf-8',)
logging.basicConfig(
handlers = [file_handler],
format = '%(asctime)s - %(levelname)s - %(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level = logging.ERROR
)
logging.error('你好')
3.3日志分割
import time
import logging
from logging import handlers
# file_handler = logging.FileHandler(filename='log_paper.log', mode='a', encoding='utf-8',)
file_handler = handlers.TimedRotatingFileHandler(filename='log_paper', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
handlers=[file_handler],
format='%(asctime)s - %(levelname)s - %(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=logging.ERROR
)
for i in range(1,100000):
time.sleep(1)
logging.error(str(i))
3.4注意事项
exc_info = True
import logging
logging.basicConfig(
''''''
)
try:
pass
except Exception as e:
msg = str(e) # 内部会调用e.__str__方法
logging.error(msg, exc_info=True) # 加入参数会把堆栈信息写入日志
4.项目结构目录
- 脚本
单可执行文件
- 配置相关 / 用户数据 / 公共代码 / 业务代码
- 多可执行文件