写Python代码的时候有这样的疑问吗?为什么数学中的+号在字符串运算中变成了拼接函数,比如'ab'+'cd',结果是abcd;而*符号变成了重复函数,例如'ab'*2,结果是abab。为什么有的对象print可以输出数据,而print自定义类对象却输出一堆看不懂的代码<__main__.MyClsobjectat0x105732250>。并不是因为系统做了特殊的定制,而是Python中有一种特殊的方法,在某些情况下会自动调用。比如在字符串类str中定义__add__方法后,当代码遇到字符串加法'ab'+'cd'时,会自动调用__add__方法完成字符串拼接。由于这种特殊方法的方法名以双下划线开头和结尾,所以也称为双下划线方法。Python中有很多双下的方法,今天我们就来详细讲解一下。Python中的double-down方法1.init方法__init__方法是很多人最先接触到的double-down方法。classA:def__init__(self,a):self.a=a当调用A()实例化一个对象时,会自动调用__init__方法完成对象的初始化。2、运算符的降倍方法在类中定义了运算符相关的降倍方法,可以直接对类对象进行加减乘除比较等操作。这里定义了一个尺子类Rule,其中包含一个属性r_len,表示尺子的长度。classRule:def__init__(self,r_len):self.r_len=r_len2.1比较运算符如果要根据尺子的长度来比较不同的尺子,需要在Rule类中定义一个比较运算符。类规则:def__init__(self,r_len):self.r_len=r_len#operatordef__gt__(self,other):returnreturnself.r_len>other.r_len#>=operatordef__ge__(self,other):lenreturnotherself.r_lenr_>四个比较运算符<,<=,>和>=在这里被定义,这样Rule对象可以和下面的代码进行比较rule1=Rule(10)rule2=Rule(5)print(rule1>rule2)#Trueprint(rule1>=rule2)#Trueprint(rule1比较rule1和rule2,rule1对象会自动调用__gt__方法,将rule2对象传递给另一个参数完成比较,下面是thedouble-downmethodofthecomparisonoperator比较运算符的double-downmethod2.2算术运算符可以支持c的加减乘除小对象。def__add__(self,other):returnRule(self.r_len+other.r_len)这里定义了__add__方法,对应+运算符,将两个标尺的长度相加,生成一个新的标尺。rule1=Rule(10)rule2=Rule(5)rule3=rule1+rule2下面是算术运算符的double-down方法2.3逆向算术运算符Rule类支持其他类型变量的加法。以__radd__方法为例def__radd__(self,other):returnself.r_len+otherrule1=Rule(10)rule2=10+rule1当程序执行10+rule1时,会尝试调用int类的__add__但是int类类没有定义添加到Rule类对象的方法,所以程序会调用+号右边的对象rule1的__radd__方法,将10传给另一个参数。所以这个算子也叫右加算子。它支持的运算符和上面的算术运算符一样,只是在方法名前加r。2.4增量赋值运算符增量赋值运算符有+=、-=、*=、/=等。def__iadd__(self,other):self.r_len+=otherreturnselfrule1=Rule(10)rule1+=5除__divmod__方法外,其他同算术运算符,在aspect名称前加i。2.4位运算符这部分支持二进制的取反、移位、或非等运算。由于Rule类不涉及位运算,我们换个例子。定义二进制字符串的BinStr类,包括表示二进制字符串的bin_str属性。classBinStr:def__init__(self,bin_str):self.bin_str=bin_strx=BinStr('1010')#创建一个二进制字符串对象print(x.bin_str)#1010为BinStr定义了一个取反运算符~#~operatordef__invert__(self):inverted_bin_str=''.join(['1'ifi=='0'else'0'foriinself.bin_str])returnBinStr(inverted_bin_str)在__invert__方法中,遍历bin_strstring,反转每个位并返回一个新的BinStr类对象。x=BinStr('1011')invert_x=~xprint(invert_x.bin_str)#0100下面是位运算符的双降法。这部分还支持反向位运算符和递增赋值位运算符,规则和算术运算符相同,这里不再赘述。3Stringrepresentation这部分涉及到两个double-down方法__repr__和__format__,在一些特殊场景下会自动调用,比如print,将对象转换成字符串。还是以BinStr为例,先写__repr__方法。def__repr__(self):decimal=int('0b'+self.bin_str,2)returnf'二进制字符串:{self.bin_str},对应十进制数:{decimal}'x=BinStr('1011')print(x)#输出:二进制字符串:1011,对应的十进制数:11程序执行print(x)时,会自动调用__repr__方法获取对象x对应的字??符串。然后编写__format__方法,该方法也将对象格式化为字符串。def__format__(self,format_spec):returnformat_spec%self.bin_strprint('{0:binarystring:%s}'.format(x))#output:binarystring:1011inthepreviousstringofthe.formatmethod当0:包含在内,__format__方法会自动调用并将字符串传递给format_spec参数。4数值转换调用int(obj)、float(obj)等方法将对象转换为对应数据类型的数据。def__int__(self):returnint('0b'+self.bin_str,2)x=BinStr('1011')print(int(x))当调用int(x)时,会自动调用__int__方法,将二进制字符串转换为十进制数。除了以上两个,还有__abs__、__bool__、__complex__、__hash__、__index__和__str__进行数值转换。__str__和__repr__一样,打印时会自动调用,但__str__的优先级更高。5Collection相关的double-down方法这部分可以定义对象的长度,获取某个位置的元素,slice等类似集合的方法。以__len__和__getitem__为例def__len__(self):returnlen(self.bin_str)def__getitem__(self,item):returnself.bin_str[item]x=BinStr('1011')print(len(x))#4print(x[0])#1print(x[0:3])#101len(x)会自动调用__len__返回对象的长度。当通过[]获取对象的元素时,会自动调用__getitem__方法,并将切片对象传递给item参数,即可以获取单个元素或切片。Set相关的double-down方法还包括__setitem__、__delitem__和__contains__。6迭代相关的doubledown方法可以使用for-in遍历对象。def__iter__(self):self.cur_i=-1returnselfdef__next__(self):self.cur_i+=1ifself.cur_i>=len(self.bin_str):raiseStopIteration()#退出迭代self.bin_strself.cur_i]x=BinStr('1011')foriinx:print(i)在x上使用for-in循环时,会先调用__iter__方法将游标cur_i设置为初始值-1,然后继续调用__next__方法来遍历self.bin_str中的每一位。这部分还有一个__reversed__方法来反转对象。def__reversed__(self):returnBinStr(''.join(list(reversed(self.bin_str))))x=BinStr('1011')reversed_x=reversed(x)print(reversed_x)#输出:二进制字符串:1101,对应的十进制数:137类相关的双降方法做web开发的朋友会用到更多类相关的双降方法。7.1实例的创建和销毁实例的创建是__new__和__init__方法,实例的销毁是__del__方法。__new__的调用早于__init__。它的作用是创建对象的实例(在内存中开辟一块空间),然后将实例传递给__init__方法,完成实例的初始化。由于__new__是类的静态方法,它可以控制对象的创建,从而实现单例模式。__del__方法在实例销毁时自动调用,可用于做一些清理和资源释放。7.2属性管理类属性的访问和设置。包括__getattr__、__getattribute__、__setattr__和__delattr__方法。__getattr__和__getattribute__的区别在于,访问类的属性时,无论该属性是否存在,都会调用__getattribute__方法,只有当该属性不存在时,才会调用__getattr__方法。7.3属性描述符控制属性访问,一般用于将属性取值控制在合理范围内。包括__get__、__set__和__delete__方法。ClassXvalidation:DEF__get__(Self,Instance,Owner):ReturnSelf.xDEF__SET__(Self,Instance,Value):IF0<=Value<=100:Self.x=ValueElse:A0,cannotbe大于100')def__delete__(self,instance):print('deleteattribute')classMyCls:x=XValidation()def__init__(self,n):self.x=nobj=MyCls(10)obj.x=101print(obj.x)#抛出异常:Exception:xcannotbelessthan0andcannotbegreaterthan100在上面的例子中,通过类属性描述符,可以控制属性x的值在[0,100]的防止违法价值。8小结以上虽然没有介绍所有的双降方式,但也算是绝大部分了。虽然double-down方法可以写任何代码,但是大家应该尽量写出和方法要求一样的代码。比如__add__方法中实现的不是对象的加法而是减法。虽然也能运行,但是会造成很大的混乱,不利于代码维护。以上就是本次分享的全部内容。觉得文章还不错的话,请关注公众号:Python编程学习圈,每日干货分享,发送“J”还能收到海量学习资料,涵盖Python电子书和教程,数据库编程、Django、爬虫、云计算等。或者去编程学习网了解更多编程技术知识。