测开之面向对象进阶篇・《魔术方法》
Posted 七月的小尾巴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了测开之面向对象进阶篇・《魔术方法》相关的知识,希望对你有一定的参考价值。
魔术方法
在类方法中__init__ 方法有什么作用?
创建对象时,自动调用对创建的对象进行初始化设置。
什么是魔术方法?
在python中,像 __init__这类双下滑线开头和结尾的方法,统一称之为魔术方法。
注意:在我们自己封装方法时,千万不要用双下划线开头或者结尾的方法定义,魔术方法时python内部自己定义的方法。
创建单例模式
我们在创建类的时候,每次调用时,都会实例化一个对象,那么如果我们要求这个类只会被实例化一次,应该怎么做呢?
class Demo(object):
__instance = None
def __new__(cls, *args, **kwargs):
# 通过重写new方法来控制类创建对象的次数
if cls.__instance is None:
instance = super().__new__(cls)
cls.__instance = instance
return cls.__instance
deom1 = Demo()
deom2 = Demo()
# 分别打印 demo1 和 demo2 的内存地址
print(id(deom1), id(deom2))
结果:
1401905908320 1401905908320
通过返回结果,我们看到他们调用的是同一个内存地址
单例模式在工作中的使用场景,假设我们类在工作中需要创建非常多的对象,不同的对象他们调用的内部方法都是相同的,比如日志模块。通常我们定义的日志模块,在不同的地方调用日志,都需要调用一个对象。在python中,如果我们通过类去创建对象,那么就是一个日志收集器。如果说我们创建多个的话,就会导致日志重复收集。
import os
import logging
from logging.handlers import TimedRotatingFileHandler, BaseRotatingHandler
import colorama
colorama.init()
class Logger:
__instance = None
sh = logging.StreamHandler()
def __new__(cls, path=None, level='DEBUG'):
"""
:param path: report path
:param args:
:param kwargs:
:return:
"""
if not cls.__instance:
cls.__instance = super().__new__(cls)
log = logging.getLogger('apin-ui')
log.setLevel(level)
cls.__instance.log = log
return cls.__instance
def set_level(self, level):
"""设置日志输出的等级"""
self.log.setLevel(level)
def set_file_handle(self, level, path):
if path:
if not os.path.isdir(path):
os.mkdir(path)
fh = TimedRotatingFileHandler(os.path.join(path, 'apin-ui.log'), when='d',
interval=1, backupCount=7,
encoding="utf-8")
fh.setLevel(level)
self.log.addHandler(fh)
# 定义handler的输出格式
formatter = logging.Formatter("%(asctime)s | 【%(levelname)s】 | : %(message)s")
fh.setFormatter(formatter)
def debug(self, message):
self.fontColor('\\033[0;34m{}\\033[0;34m{}\\033[0;34m{}')
self.log.debug(message)
def info(self, message):
self.fontColor('\\033[0;32m{}\\033[0;32m{}\\033[0;32m{}')
self.log.info(message)
def warning(self, message):
self.fontColor('\\033[0;33m{}\\033[0;43m{}\\033[0;33m{}')
self.log.warning(message)
def error(self, message):
self.fontColor('\\033[0;31m{}\\033[0;41m{}\\033[0;31m{}')
self.log.error(message)
def exception(self, message):
self.fontColor('\\033[0;31m{}\\033[0;41m{}\\033[0;31m{}')
self.log.exception(message)
def critical(self, message):
self.fontColor('\\033[0;35m{}\\033[0;45m{}\\033[0;35m{}')
self.log.critical(message)
def fontColor(self, color):
# 不同的日志输出不同的颜色
formatter = logging.Formatter(color.format("%(asctime)s| ", "【%(levelname)s】", " | : %(message)s"))
self.sh.setFormatter(formatter)
self.log.addHandler(self.sh)
def print_info(msg):
print('\\033[0;32m{}'.format(msg))
def print_waring(msg):
print('\\033[0;33m{}'.format(msg))
def print_error(msg):
print('\\033[0;31m{}'.format(msg))
if __name__ == '__main__':
logger = Logger()
logger.debug('debu等级日志')
logger.info('info日志')
logger.warning('warning日志')
logger.error('error日志')
logger.critical('CRITICAL日志')
上下文管理器
在我们使用python中的with open方法去打开文件,有没有思考过,为什么with open方法打开文件,会自动关闭?
这里我们就需要了解到上下文管理器的概念:
上下文管理器是一个python对象,为操作提供了额外的上下文信息。这种额外信息,在使用 with 语句初始化上下文,以及完成 with 代码块中采用所有可调用的形式。
- object.enter(self)
输入与次对象相关的上下文。如果存在的话,with 语句将绑定该方法的返回值到该一句的as子句子指定的目标。 - object.exit(self, exc_type, exc_val, exc_tb)
exc_type: 异常类型
exc_val: 异常值
exc_tb:异常回溯追踪
下面我们来手动实现一个文件操作:
class OpenFile(object):
"""手写实现文件操作的上下文"""
def __init__(self, filename, method):
# 初始化打开文件
self.file = open(filename, method)
# 启动上下文时,讲打开的对象返回出去
def __enter__(self):
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
python 中 str 魔术方法的使用
再python中假设,我们定义一个列表,我们可以看到可以直接将列表中的数据打印出来。
li = list([11, 22, 33, 44])
print(li)
打印:[11, 22, 33, 44]
但是如果说我们定义一个类呢,再类中我们定义一个初始化方法,此时我们想要获取初始化方法的内容,我们给类定义一个实例化对象,然后进行打印,可以看到打印出来了对象的地址。
class Myetest:
def __init__(self, name):
self.name = name
m = Myetest("test")
print(m)
结果:<__main__.Myetest object at 0x00000267CDDE8820>
那么我们如何实现打印初始化方法中的数据呢?可以使用 __str__方法。
class Myetest:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
m = Myetest("test")
print(m)
结果:test
注意:__str__ 方法只能返回字符串类型的数据,如果是其他类型数据,会抛异常
以上是关于测开之面向对象进阶篇・《魔术方法》的主要内容,如果未能解决你的问题,请参考以下文章