魔术方法
双下划线开头和结尾的方法(又叫特殊方法、魔法方法;是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'>