python魔法方法有什么用
1、魔法方法是什么?
魔法方法是一种特殊的方法,可以为你的类增加魔力。如果你的对象实现了这些方法中的一种(重载),那么这种方法将在特殊情况下被使用 Python 你可以定义你想要的行为,这一切都是自动触发的。它们通常被两条下划线包围(例如 __init__,__lt__),Python的魔法方法非常强大,因此了解其使用方法也变得尤为重要!
2、__init__(self[, ...]),__new__(cls[, ...]),__del__(self)
(1)__init__ 当一个例子被创建时,构造器是初始化的。但这并不是实例调用的第一种方法,__new__是实例对象调用的第一种方法,只取下 cls 将其他参数传递给参数 __init__。 __new__很少使用,但也有合适的场景,尤其是当它继承了像元组或字符串这样不经常改变的类型时。
(2)__new__ 使用时注意以下四点:
a、__new__ 是对象实例化时调用的第一种方法;
b、它的第一个参数是这一类,其他参数用于直接传递 __init__ 方法;
c、__new__ 返回一个构建示例;
d、__new__ 决定是否使用它 __init__ 方法,因为 __new__ 如果可以调用其他类别的结构方法或直接返回其他实例对象作为此类实例, __new__ 如果没有返回实例对象,则__init__ 不被调用;
e、__new__ 它主要用于继承一种不可改变的类型,如一种 tuple 或者 string。
相关推荐:Python平台
__new__实现单例模式(无论实例多少次,结果都是同一个例子)
单例模式(Singleton Pattern)它是一种常用的软件设计模式,其主要目的是确保某一类只有一个例子。当您希望在整个系统中只有一个例子时,单个例子对象可以派上用场。
例如,服务器程序的配置信息存储在文件中,客户端通过一个文件存储 AppConfig 类别读取配置文件的信息。如果配置文件的内容需要在程序运行过程中使用,也就是说,需要在许多地方创建 AppConfig 对象的例子,这就导致系统中存在多个问题 AppConfig 例子对象,这将严重浪费内存资源,特别是在配置大量文件的情况下。事实上,类似 AppConfig 我们希望在程序运行过程中只有一个实例对象。
举例:
classPerson(object): def__init__(self,name,age): self.name=name self.age=age def__new__(cls,*args,**kwargs): ifnothasattr(cls,'instance'): cls.instance=super().__new__(cls) returncls.instance a=Person('p1',21) b=Person('p2',22) print(a==b,a.name==b.name)#这里的印刷结果都是True,可以看出A和B都是相同的例子(例子B涵盖了例子A)。 #单例作用: #一是通过线程同步控制资源的并发访问,控制资源的使用; #控制实例产生的数量,达到节约资源的目的; #第三,作为通信媒体,即数据共享。例如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源。 #应用场景: #Pythonloger是用来记录日志的单例模式 #一般情况下,线程池、数据库连接池等资源池也采用单例模式 #Windows的资源管理器是单例模式 #网站计数器
(3)__del__ 当实例被销毁时,调用析构器。
3、__call__(self[,args ...]),__getitem__(self,key),__setitem__(self,key,value)
(1)__call__ 允许一个类的例子像函数一样被调用,如下:
classPerson(object): def__init__(self,name,age): self.name=name self.age=age self.instance=add def__call__(self,*args): returnself.instance(*args) defadd(args): returnargs[0]+args[1] a=Person('p1',20) print(a(1,2)))) #这里将打印3 #可以看出,创建a的对象后,如果定义__call__函数对象可以像函数一样调用。
(2)__getitem__ 在容器中定义指定元素的行为相当于self[key],如下:
classPerson(object): def__init__(self,name,age): self.name=name self.age=age self._registry={ 'name':name, 'age':age } def__call__(self,*args): returnself.instance(*args) def__getitem__(self,key): ifkeynotinself._registry.keys(): raiseException('Pleaseregistrythekey:%sfirst!'%(key,)) returnself._registry[key] a=Person('p1',20) print(a['name'],a['age']) #这里打印的是'p1'20 #可见__getitem__使实例能够像字典一样访问
(3)__setitem__ 设置容器中指定元素的行为相当于self[key] = value 。
4、__getattr__(self,name),__getattribute__(self,name),__setattr__(self,name,value),__delattr__(self,name)
(1)__getattr__ ():当用户试图访问一个不存在的属性时触发;
(2)__getattribute__(): 访问时触发一个属性(无论是否存在);
(3)__setattr__ ():当设置属性时,触发;
(4)__delattr__ ():当一个属性被删除时触发。
classPerson(object): def__init__(self,name,age): self.name=name self.age=age self._registry={ 'name':name, 'age':age } def__getattribute__(self,item): #注意不要在这里访问属性,比如self.__dict__[item] #因为self.__dict____还是会被___getattribute__拦截,这将陷入死循环 returnobject.__getattribute__(self,item) def__getattr__(self,item): print("don'thavetheattribute",item) returnFalse def__setattr__(self,key,value): self.__dict__[key]=value a=Person('p1',20) print(a.cs)#don'将在这里打印;thavetheattributecs,Falseetecs a.cs='测试'#这里设置的属性值为'测试' print(a.cs)#这里将打印'测试'