No.23单例模式&日志模块

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.项目结构目录

  • 脚本

  • 单可执行文件

    • 配置相关 / 用户数据 / 公共代码 / 业务代码

  • 多可执行文件

猜你喜欢

转载自www.cnblogs.com/elliottwave/p/12528263.html