魔术方法、单例模式、上下文管理器协议

魔术方法
  双下划线开头和结尾的方法(又叫特殊方法、魔法方法;是Python事先去实现底层的一些方法,自己去定义方法的时候最好不要使用双下划线开头和结尾),不需要手动去调用,都是在特定的情况下触发的。

# 类实例化对象的过程:
#  1、调用__new__创建对象
#  2、调用__init__初始化对象(init中的self就是new的返回值)
# 一般情况下不要去定义__new__方法,如果定义了,一定要在new中返回对象
# 也可以返回其他如一个空列表,这样创建的对象就自动有append等列表特有的方法,但是不会这么做
# 如果__new__方法中没有返回对象,则不会执行到__init__去初始化对象,没有返回值则打印为None

class Demo(object):

    def __init__(self):
        print('init')

    def __new__(cls):
        print('new')
        obj = super().__new__(cls)  # 调用父类
        return obj  # 返回对象


dd = Demo()
print(dd)

单例模式
  一个类只能创建一个对象,无论之后创建多少个对象,内存地址都是指向的第一次创建的对象,区别于工厂模式。
单例模式的实现
  1、重写父类__new__方法
  2、通过装饰器去实现,使用该装饰器的类都可以实现单例模式
单例模式的作用
  节约内存开销;日志收集器可以说明单例模式的用处。

# 可以重写父类__new__方法中限制创建对象,从而实现该类的单例模式
class Demo1:
    __instance = None  # 变量以__开头为私有属性,在类外部不可更改

    def __new__(cls, *args, **kwargs):
        # 先判断该类有没有创建过对象
        if not cls.__instance:
            cls.__instance = super().__new__(cls)  # new方法中一定要带 cls
        return cls.__instance

res1 = Demo1()
# 私有属性不可在类外部更改,但是也不会报错,如果不使用私有属性可能会在类外部重新赋值
# 保险起见变量名设置为私有属性
res1.__instance = None
res2 = Demo1()
print(id(res1),id(res2))  # 地址相同
# 通过闭包实现单例模式,类被装饰后只能创建一个对象
def single(cls):
    def wrapper(*args, **kwargs):
        if not hasattr(cls, '__instance'):
            cls.__instance = cls(*args, **kwargs)
        else:
            cls.__instance.__init__(*args, **kwargs)  # 刷新属性
        return cls.__instance
    return wrapper

上下文管理器协议
  由__enter__方法(启动上下文时自动调用)和__exit__方法(退出上下文时自动调用)构成。

# 上下文管理器协议的构成
# __enter__方法
# __exit__方法
# 使用with去打开文件进行操作完后会自动关闭的原因就是with启动了文件操作对象的上下文管理器
# 如果说一个对象实现了__enter__方法和__exit__方法,那么这个对象就实现了上下文管理器协议
# 就可以使用with这个关键字来开启对象的上下文管理。
# 代码如下

class FileOpen:

    def __init__(self, file, mode, encoding):
        self.file = file
        self.mode = mode
        self.encoding = encoding

    def __enter__(self):
        # 使用open时对于第三个参数,指定编码方式必须要加encoding=“utf-8”
        # 如果不加encoding=,则解释器默认认为第三个参数为指定buffering,这个变量本身要传入一个整形变量才行
        # 会报TypeError: an integer is required (got type str)错误
        # 而对于二进制读取的模式,则不能指定编码方法,传前面两个参数即可  以上为使用open的踩坑点总结
        self.io = open(self.file, self.mode, encoding=self.encoding)
        return self.io

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        exit方法带三个参数
        :param exc_type:异常类型
        :param exc_val:异常提示
        :param exc_tb:异常溯源对象
        :return:
        """
        self.io.close()


with FileOpen('zhuangshiqi.py', 'r', encoding='utf-8') as f:
    print(f)  # <_io.TextIOWrapper name='zhuangshiqi.py' mode='r' encoding='utf-8'> 文件的句柄
# 当使用with操作这个对象的时候,会启动上下文管理器协议,先调用__enter__方法并把返回值赋值给f,所以在enter可以做打开文件的操作
# 当把with里面的代码执行结束后会自动触发__exit__方法,可以在exit里做关闭文件的操作
# 即使with里面的代码出错了,仍会调用exit方法,在exit方法里带三个参数可抛出该异常的信息

__str__方法 

# __str__方法,print输出到控制台的内容就是__str__的返回值
# __str__方法要写返回值,且返回值的类型只能是字符串
class MyStr:

    def __init__(self, name):
        self.name = name

daxigua = MyStr('大西瓜')
print(daxigua)  # <__main__.MyStr object at 0x000001DAA6D3D940>

class MyStr1:

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return str(self.name)
daxigua1 = MyStr1('大西瓜1')
print(daxigua1)  # 大西瓜1
print(type(daxigua1))  # <class '__main__.MyStr1'>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值