当前位置: 首页 > 科技观察

说说Python中常用的魔术方法

时间:2023-03-20 12:34:34 科技观察

什么是魔术方法?魔术方法(MagicMethods)是Python中的内置函数,一般以双下划线开头和结尾,如__init__、__del__等,之所以称为魔术方法是因为这些方法会在特定操作时自动调用被执行。在Python中,可以使用dir()方法查看一个对象的所有方法和属性,其中双下划线以该对象的魔术方法开始和结束。以字符串对象为例:>>>dir("hello")['__add__','__class__','__contains__','__delattr__','__doc__','__eq__','__format__','__ge__','__getattribute__','__getitem__','__getnewargs__','__getslice__','__gt__','__hash__','__init__','__le__','__len__','__lt__','__mod__','__mul__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__rmod__','__rmul__','__setattr__','__sizeof__','__str__','__subclasshook__','_formatter_field_name_split','_formatter_parser','capitalize','center','count','decode','encode','endswith','expandtabs','find','format','index','isalnum','isalpha','isdigit','islower','isspace','istitle','isupper','join','ljust','lower','lstrip','partition','replace','rfind','rindex','rjust','rpartition','rsplit','rstrip','split','splitlines','startswith','strip','swapcase','title','translate','upper','zfill']可以看到string对象有__add__方法,所以可以直接使用Python中对字符串对象的“+”操作。当Python识别出“+”操作时,会调用这个当需要对象的__add__方法时,我们可以在自己的类中重写__add__方法来达到预期的效果。A类(对象):def__init__(self,str):self。str=strdef__add__(self,other):print('覆盖添加方法')returnself.str+"---"+other.str>>>a1=A("hello")>>>a2=A("world")>>>print(a1+a2)>>>覆盖添加方法>>>"hello---world"我们重写了__add__方法。当Python识别到“+”操作时,会自动调用重写后的__add__方法。可以看出,当类或对象的某些事件被触发后,魔术方法就会自动执行。如果要根据自己的程序自定义一个具有特殊功能的类,就需要重写这些方法。使用魔术方法,我们可以轻松地为类添加特殊功能。常用的魔术方法1.构造和初始化__new__,__init__这两个魔术方法经常被用来初始化类。上面我们创建a1=A("hello")时,但是第一次调用的是__new__;初始化一个类分为两步:a.调用该类的new方法,返回该类b的实例对象。调用本类的类init方法初始化实例对象__new__(cls,*args,**kwargs)至少需要一个cls参数,代表传入的类。后两个参数传递给__init__。在__new__中,可以决定是否继续调用__init__方法。只有当__new__返回当前类cls的实例时,您才会调用__init__。结合__new__方法的特点,我们可以通过重写__new__方法来实现Python的单例模式:classSingleton(object):def__init__(self):print("__init__")?def__new__(cls,*args,**kwargs):?print("__new__")?ifnothasattr(Singleton,"_instance"):?print("Createanewinstance")?Singleton._instance=object.__new__(cls)?returnSingleton._instance>>>obj1=Singleton()>>>__new__>>>创建新实例>>>__init__>>>obj2=Singleton()>>>__new__>>>__init__>>>print(obj1,obj2)>>>(<__main__.Singletonobjectat0x0000000003599748>,<__main__.Singletonobjectat0x0000000003599748>)可以看出虽然创建了两个对象,但是两个对象的地址是相同的。2.控制属性访问这种魔术方法主要在访问、定义和修改对象的属性时起作用。主要是:__getattr__(self,name):定义当用户试图获取一个属性时的行为。__getattribute__(self,name):定义访问该类的属性时的行为(先调用该方法查看属性是否存在,如果不存在则调用getattr)。__setattr__(self,name,value):定义设置属性时的行为。在初始化一个属性如self.a=a或修改一个实例属性如ins.a=1时,本质就是调用魔术方法self.__setattr__(name,values);当实例访问某个属性如ins.a时,本质就是调用magic方法a.__getattr__(name)3.容器类操作有一些方法可以让我们定义自己的容器,比如Python内置的List、元组、字典等;容器分为可变容器和不可变容器。如果自定义一个不可变容器,那么只能定义__len__和__getitem__;定义一个可变容器,除了不可变容器的所有魔法方法外,还需要定义__setitem__和__delitem__;如果容器是可迭代的。__iter__也需要定义。__len__(self):返回容器的长度__getitem__(self,key):当需要执行self[key]调用容器中的对象时,调用此方法__setitem__(self,key,value):当required执行self[key]=value时,会调用__iter__(self)方法:当容器可以执行forxincontainer:,或使用iter(container)时,需要定义此方法。下面是一个实现容器的例子,容器具有List的通用功能,同时增加了一些其他的功能,比如访问第一个元素,最后一个元素,记录每个元素被访问的次数等。classSpecialList(object):def__init__(self,values=None):self._index=0ifvaluesisNone:self.values=[]else:self.价值观=自我价值观。计数={}。fromkeys(range(len(self.values)),0)def__len__(self):#通过len(obj)访问容器长度returnlen(self.values)def__getitem__(self,key):#通过访问容器长度obj[key]Objectself.count[key]+=1returnself.values[key]def__setitem__(self,key,value):#通过obj[key]=value修改容器中的对象self.values[key]=valuedef__iter__(self):#通过for循环遍历容器returniter(self.values)def__next__(self):#迭代的具体细节#如果__iter__返回self,则必须实现此方法ifself._index>=len(self.values):raiseStopIteration()value=self.values[self._index]self._index+=1返回值defappend(self,value):self.values.append(value)defhead(self):#获取第一个元素returnself.valuees[0]deflast(self):#获取最后一个元素returnself.values[-1]该方法的使用场景主要用于需要定义满足要求的容器类数据结构时,例如,可以尝试自定义树结构、链表等数据结构的实现(都存在于集合中),或者项目中需要自定义的一些容器类型总结魔术方法可以简化Python代码中的代码,提高代码的可读性。在三方库中可以看到很多魔术方法的使用。因此,当前的文章只是一个扔掉的东西。真正的使用需要在开源的优秀源码和自己的工程实践中加深理解并适当应用。