python基础语法18 类的内置方法(魔法方法),单例模式
类的内置方法(魔法方法):
凡是在类内部定义,以__开头__结尾的方法,都是类的内置方法,也称之为魔法方法。
类的内置方法,会在某种条件满足下自动触发。
内置方法如下:
__new__: 在__init__触发前,自动触发。 调用该类时,内部会通过__new__产生一个新的对象。
__init__: 在调用类时自动触发。 通过产生的对象自动调用__init__()
class Demo(object): # 条件: __new__: 在__init__触发前,自动触发。 def __new__(cls, *args, **kwargs): print('此处是__new__方法的执行') # python内部通过object调用内部的__new__实现产生一个空的对象 ---> 内存地址 return object.__new__(cls,*args,**kwargs) # 条件: __init__: 在调用类时自动触发。 def __init__(self): print('此处是__init__方法的执行') demo_obj=Demo() '''result: 此处是__new__方法的执行 此处是__init__方法的执行 '''
__getattr__: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。
class Demo(object): # __getattr__: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。 def __getattr__(self, item): print('此处是__getattr__方法的执行') print(item)
# return 想要返回的值 return '别闹,没有该属性' demo_obj=Demo() print(demo_obj.x) ''' 此处是__getattr__方法的执行 x 别闹,没有该属性 ''' demo_obj.x=3 print(demo_obj.x) # 3
条件: __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。
注意: 只要__getattr__ 与 __getattribute__ 同时存在类的内部,只会触发__getattribute__。
class Demo(object): # 条件: __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。 def __getattribute__(self, item): print('此处是__getattribute__方法的执行') print(item,'<-----打印属性名字') # return self.__dict__[item] # 注意: 此处不能通过 对象.属性,否则会产生递归调用,程序崩溃 # return getattr(self.item) # getattr: 内部调用了 ----> __getattribute__, 也会递归 # 注意: 只要__getattr__ 与 __getattribute__ 同时存在类的内部,只会触发__getattribute__。 demo_obj=Demo() print(demo_obj.x) ''' 此处是__getattribute__方法的执行 x <-----打印属性名字 None ''' demo_obj.x=3 print(demo_obj.x) # 3 ''' 此处是__getattribute__方法的执行 x <-----打印属性名字 None '''
条件: 当 “对象.属性 = 属性值” , 添加或修改属性时触发
class Demo(object): # 条件: 当 “对象.属性 = 属性值” , 添加或修改属性时触发 def __setattr__(self, key, value): # key---> 对象.属性名 value ---》 属性值 print('# key---> 对象.属性名 value ---》 属性值') print(key,value) #self.key=value #产生递归 self.__dict__[key]=value # 此处是对 对象的名称空间 ---》 字典进行操作 demo_obj=Demo() # print(demo_obj.x) demo_obj.x=3 ''' # key---> 对象.属性名 value ---》 属性值 x 3 ''' print(demo_obj.x) # 3
条件: 在调用对象 “对象 + ()” 时触发。
class Demo(object): # 条件: 在调用对象 “对象 + ()” 时触发。 def __call__(self, *args, **kwargs): print('此处是__call__方法的执行') #调用对象时返回的值 return [1,2,3,4,5] demo_obj=Demo() res=demo_obj() # 此处是__call__方法的执行 print(res) # [1, 2, 3, 4, 5]
条件: 在打印对象时触发。
class Demo: # 条件: 在打印对象时触发。 #注意:该方法必须要有一个"字符串"返回值 def __str__(self): print('此处是__str__方法的执行') return '111' demo_obj=Demo() print(demo_obj) ''' 此处是__str__方法的执行 111 '''
在对象通过 “对象[key]” 获取属性时触发。
class Demo: # 在对象通过 “对象[key]” 获取属性时触发。 def __getitem__(self, item): print('此处是__getitem__方法的执行') print(item) return self.__dict__[item] demo_obj=Demo() demo_obj.x=10 res=demo_obj['x'] ''' 此处是__getitem__方法的执行 x ''' print(res) # 10
在对象通过 “对象[key]=value值” 设置属性时触发。
class Demo: # 在对象通过 “对象[key]=value值” 设置属性时触发。 def __setitem__(self, key, value): print('此处是__setitem__方法的执行') print(key,value) self.__dict__[key] = value demo_obj=Demo() demo_obj['y']=300 ''' 此处是__setitem__方法的执行 y 300 ''' print(demo_obj.y) # 10
单例模式:
指的是在确定 "类中的属性与方法" 不变时,需要反复调用该类,
产生不同的对象,会产生不同的内存地址,造成资源的浪费。
让所有类在实例化时,指向同一个内存地址,称之为单例模式。 ----> 无论产生多个对象,都会指向 单个 实例。
- 单例的优点:
节省内存空间。
#反面案例
class Foo: def __init__(self,x,y): self.x=x self.y=y foo_obj1=Foo(10,20) print(foo_obj1) # <__main__.Foo object at 0x0000000001D85CF8> foo_obj2=Foo(10,20) print(foo_obj2) # <__main__.Foo object at 0x00000000021BCC88>
单例模式: (面试让你手撸,一定要背下来。)
1.通过classmethod
2.通过装饰器实现
3.通过__new__实现
4.通过导入模块时实现
5.通过元类实现。
classmethod实现
class MySQL: # 一个默认值,用于判断对象是否存在, 对象不存在证明值是None # __instance是类的属性,可以由类来调用 __instance = None # ---》 若已有对象会返回给它 ---》 obj # __instance = obj def __init__(self,host,port): self.host=host self.port=port @classmethod def singleton(cls,host,port): # 单例方法 ---》 类方法 # 判断__instance中若没有值,证明没有对象 if not cls.__instance: # 产生一个对象并返回 obj=cls(host,port) # None ---> obj cls.__instance=obj # 若__instance中有值,证明对象已经存在,则直接返回该对象 return cls.__instance def start_mysql(self): print('启动mysql') def close(self): print('关闭mysql') obj1=MySQL.singleton('180.101.49.12',443) print(obj1) # <__main__.MySQL object at 0x000000000255D160> obj2=MySQL.singleton('180.101.49.12',443) print(obj2) # <__main__.MySQL object at 0x000000000255D160>
或者:
class Borg: def __new__(cls, *args, **kwargs): if not hasattr(cls,'_instance'): ob = super(Borg,cls) cls._instance = ob.__new__(cls,*args,**kwargs) return cls._instance # if not hasattr(cls,'_instance'): # # 造一个空对象 # cls._instance = object.__new__(cls) # return cls._instance class MyClass(Borg): def __init__(self): self.a = 1 obj1 = MyClass() obj2 = MyClass() print(obj1) print(obj2)
__new__实现
# __new__创造单例模式 class Singleton: __instance = None @classmethod # 此处可以不加此装饰器,__new__默认为类方法 def __new__(cls, *args, **kwargs): if not cls.__instance: # 造一个空对象 cls.__instance = object.__new__(cls) return cls.__instance obj1= Singleton() obj2= Singleton() obj3= Singleton() print(obj1) # <__main__.Singleton object at 0x000000000255D048> print(obj2) # <__main__.Singleton object at 0x000000000255D048> print(obj3) # <__main__.Singleton object at 0x000000000255D048>
装饰器实现
def singleton(cls): _instance = {} #此处必须为可变类型 def inner(*args,**kwargs): if cls not in _instance: _instance[cls] = cls(*args,**kwargs) return _instance[cls] return inner @singleton class Father: pass print(Father()) # <__main__.Father object at 0x0000000001DA5D68> print(Father()) # <__main__.Father object at 0x0000000001DA5D68>
为什么不能用_instance=None赋值说明
def singleton(cls): _instance = None #此处必须为可变类型 def inner(*args,**kwargs): if not _instance: # 报错,因为_instance优先指向内置空间的对象,也就是下面的_instance,没有就报错,无解!此处必须用字典等方法 _instance = cls(*args,**kwargs) return _instance return inner @singleton class Father: pass print(Father()) print(Father())
模块导入
# 以下为singleton模块 class SingletonCls: pass obj = SingletonCls() # 以下为测试程序 from singleton模块 import obj print(obj) print(obj)