Python: 类封装技巧, 以 Log 类为例

2024-06-11 18:23:45 浏览数 (2)

在软件开发中,日志记录是一个非常重要的部分。良好的日志记录可以帮助开发者在调试和维护代码时更好地理解程序的行为。本文将通过一个具体的日志记录类 MyLog,介绍如何在 Python 中使用类封装技巧来实现一个功能强大的日志记录系统。

什么是封装?

封装是面向对象编程(OOP)的四大基本原则之一。封装通过将数据和操作数据的方法包装在一个单独的单元中,即类中,来保护数据不被外部代码直接访问和修改。通过这种方式,我们可以隐藏类的内部实现细节,仅暴露必要的接口给外部使用者,从而提高代码的可维护性和重用性。

MyLog 类的设计

我们设计的 MyLog 类实现了单例模式(Singleton Pattern),保证在应用程序的整个生命周期中只会存在一个 MyLog 实例。下面是 MyLog 类的完整代码:

代码语言:javascript复制

python
import os
import logging
import sys

# 定义常量
PATH = './logs'
NAME = 'default_log'
FMT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
DATEFMT = '%Y-%m-%d %H:%M:%S'

class MyLog(object):
    _instance = None
    
    def __new__(cls, *args, **kw):
        if cls._instance is None:
            MyLog._instance = object.__new__(cls)
        return MyLog._instance

    def __init__(self, config=None):
        if config:
            path = config.get('logpath')
            name = config.get('logname')
        else:
            path = PATH
            name = NAME

        if not os.path.exists(path):
            os.mkdir(path)
           
        self.logger = logging.getLogger()
        self.formatter = logging.Formatter(fmt=FMT, datefmt=DATEFMT)
        self.log_filename = '{0}/{1}.log'.format(path, name)

        self.logger.addHandler(self.get_file_handler(self.log_filename))
        self.logger.addHandler(self.get_console_handler())
        self.logger.setLevel(logging.DEBUG)

    @classmethod
    def get_instance(cls):
        return cls._instance

    def get_file_handler(self, filename):
        filehandler = logging.FileHandler(filename, encoding="utf-8")
        filehandler.setFormatter(self.formatter)
        return filehandler

    def get_console_handler(self):
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setFormatter(self.formatter)
        return console_handler

单例模式的实现

单例模式确保一个类只有一个实例,并提供一个全局访问点。我们通过重写 __new__ 方法来实现这一点:

代码语言:javascript复制

python
def __new__(cls, *args, **kw):
    if cls._instance is None:
        MyLog._instance = object.__new__(cls)
    return MyLog._instance

__new__ 方法中,我们检查类变量 _instance 是否为 None,如果是,则创建一个新实例并赋值给 _instance,否则直接返回已有实例。

构造函数

构造函数 __init__ 用于初始化日志记录器。在初始化过程中,我们可以传递一个配置字典来指定日志路径和日志文件名:

代码语言:javascript复制

python
def __init__(self, config=None):
    if config:
        path = config.get('logpath')
        name = config.get('logname')
    else:
        path = PATH
        name = NAME

    if not os.path.exists(path):
        os.mkdir(path)
    
    self.logger = logging.getLogger()
    self.formatter = logging.Formatter(fmt=FMT, datefmt=DATEFMT)
    self.log_filename = '{0}/{1}.log'.format(path, name)

    self.logger.addHandler(self.get_file_handler(self.log_filename))
    self.logger.addHandler(self.get_console_handler())
    self.logger.setLevel(logging.DEBUG)

封装日志处理器

我们通过封装两个方法来分别创建文件处理器和控制台处理器:

代码语言:javascript复制

python
def get_file_handler(self, filename):
    filehandler = logging.FileHandler(filename, encoding="utf-8")
    filehandler.setFormatter(self.formatter)
    return filehandler

def get_console_handler(self):
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setFormatter(self.formatter)
    return console_handler

这些方法分别返回配置好的文件处理器和控制台处理器,并在构造函数中将它们添加到日志记录器中。

使用示例

下面是如何使用 MyLog 类的一个示例:

代码语言:javascript复制

python
# 使用 MyLog 类并指定日志路径和文件名
config = {
    'logpath': './my_log_directory',
    'logname': 'my_log_file'
}
logger = MyLog(config).logger

# 示例日志记录
logger.debug("This is a debug message.")
logger.info("This is an info message.")
logger.warning("This is a warning message.")
logger.error("This is an error message.")
logger.critical("This is a critical message.")

在这个示例中,我们创建了一个包含日志路径和日志文件名的配置字典 config,并通过 MyLog 类初始化日志记录器。随后,我们可以使用这个日志记录器记录不同级别的日志信息。

总结

通过以上示例,我们展示了如何在 Python 中使用类封装技巧实现一个功能强大的日志记录系统。封装不仅提高了代码的可维护性和重用性,还使得日志记录器的配置和使用更加灵活和简洁。在实际开发中,掌握这些技巧将帮助你写出更优雅和高效的代码。

0 人点赞