Python进阶话题杂谈(三)实用的特殊方法重载

1  普通运算符的重载

运算符重载并不是一个很简单的话题,但大多数的特殊情况并不实用,本文只讨论较常用的运算符重载。首先,Python中的各种数学运算,包括加减乘除等,都对应着某个方法调用。如1 + 2实际上对应着形如1.__add__(2)的调用。所以,在程序中,用户也可以修改这些函数,从而自定义这些运算符号的行为。下面以__add__与__radd__为例,讨论这样的操作。

当一个类重写了__add__方法后,就可以对类实例使用加号运算,__add__方法应返回一个运算后的结果:

class Test:

    def __add__(self, other):

        return 1 + other

print(Test() + 10)

__add__方法有两个形参,分别对应于加号前后的两个值,所以上例中的__add__只是简单的把加号后值加1的结果返回,输出为11。

__radd__方法不太常用,这里仅作简要说明。当执行加法运算时,实际上是以self.__add__(other)的形式调用了加号左值的__add__方法,而如果由于加号两边对象不一致(如numpy中的ndarray可以与Python list进行运算),加号左值并没有定义__add__方法时,此时就会颠倒加号的左右值,并尝试调用加号右值的__radd__方法。例如上文中的Test() + 10,如果换成10 + Test(),则调用将失败,因为int类型不能以Test()作为第二参数进行__add__方法调用。此时,如果Test类还定义了__radd__方法:

class Test:

    def __add__(self, other):

        return 1 + other

    def __radd__(self, other):

        return 1 + other

则此时如果进行10 + Test(),由于10.__add__(Test())将调用失败,那么就会尝试Test().__radd__(10),颠倒左右参数,并调用加号右值的__radd__方法。故大部分情况下,__add__和__radd__方法的定义都是类似的。在实际情况中,如果考虑到可能存在混合类型运算时,则可能需要考虑再定义__radd__方法。

2  增强赋值运算符的重载

增强赋值运算在很多编程语言中都有体现,其是一类由运算符加上等号组成的自身运算符。此类运算符同时执行运算与赋值操作,即对self本身进行运算与赋值。增强赋值运算符与普通运算符在重载时唯一的区别在于:普通运算符返回的是运算结果,而增强赋值运算符返回的一定是self,这个self的值已经通过运算而改变,返回的self将通过赋值覆盖掉原先的self。下面以__iadd__方法为例讨论增强赋值运算符的重载:

class Test:

    def __init__(self, num):

        self.num = num

    def __add__(self, value):

        return self.num + value

    def __iadd__(self, value):

        self.num += value

        return self

testObj = Test(2)

testObj += 3

print(testObj.num)

上例中,__iadd__直接对self进行运算操作,改变了self中的某些值,然后返回self本身。所以返回的这个self在增强赋值运算之后会直接覆盖掉运算符左值,从而实现自身值的改变。而对比__add__方法,其仅仅返回了一个加法运算的结果,并不改变self本身。

3  __repr____str__的重载

__repr__与__str__分别对应着Python中的repr与str函数调用。关于这两个函数的区别,一般上认为:repr是生成“适合解释器阅读的格式”,而str则生成“适合用户阅读的格式”,这样的解释很模糊,且在实际使用中并不需要特别关注这两个函数的功能。因为绝大多数情况下,用户一般都只会调用str函数而非repr函数,且print函数的输出样式也与str函数的返回值一致,故以下主要针对__str__方法进行讨论。

在用户自定义的类型中,__str__方法一般只与print函数连用,起到明确、美化输出的作用。默认情况下,如果不定义__str__方法,则输出某个类实例时会显示“”这样的字符串,这就是print函数对当前对象调用__str__方法的结果。而如果需要美化输出,就可以重写__str__方法,返回一个期望的字符串:

class Test:

    def __init__(self, num):

        self.num = num

    def __str__(self):

        return '[%d]' % self.num

print(Test(2))

上例中,通过重载__str__方法,使得print(Test(2))时,不再输出“”这样的字符串,而是输出了自定义的“[2]”字符串。

由于一般情况下均不关心__str__与__repr__的区别,故在重载__str__方法后,往往只需要将__repr__方法也绑定到__str__方法上即可:

__repr__ = __str__

同理,重载__repr__方法,然后__str__ = __repr__,也是可以的。

4  __call__的重载

__call__方法的重载应用场合较少,本文只做简要讨论。

首先,Python中针对一个对象,可以使用多种“符号后缀语法”,这些语法背后都分别对应着一个或一系列的方法调用。如一个对象后接“[...]”,则对应着__*item__方法系列;后接“.”,则对应着__*attr__与__getattribute__方法系列;而如果一个对象后接“(...)”,则对应着代表函数调用的__call__方法。

当重载一个类的__call__方法后,这个类的对象就可以当做一个函数一样被调用,也可为__call__方法定义形参,则实际调用中就可以传入相对应的实参:

class Test:

    def __init__(self, num):

        self.num = num

    def __call__(self, value):

        print(self.num, value)

Test(2)('call')

当__call__被定义后,Test(2)作为一个类实例,就可以当做函数一样调用,并可传入相应的参数。上述代码的调用结果即为输出“2 call”。


2018年6月于苏州

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,218评论 4 16
  • 五月天在唱着 “你不是真正的快乐,你的笑只是你穿的保护色”我不知道,阿信当时在写这首歌时是否是真的不快乐,但是此刻...
    顾你安稳阅读 221评论 1 3
  • 换了同桌的日子一开始没有什么不一样 我开始在史川身上寻开心 比如在他写作业写的认真的时候突然在他背上重重的拍一下 ...
    今天也不想学习阅读 266评论 0 0
  • 感恩今天是双11,大家可以尽情的购物,享受淘宝的盛宴。感恩今天为朋友在淘宝上购买到了合适的产品,希望他们可以满意。...
    武丹yoyo阅读 166评论 0 4
  • 这几天搬家,从柜子里翻出的一堆的登机牌 想想,做旅游的这几年,确实也飞了挺多地方。第一次飞机团,广州飞北京。第一次...
    罗萍_feaf阅读 441评论 0 0