QQ登录

只需一步,快速开始

开启左侧

Python学习第六十天—类和对象9-运算相关的魔法方法(上)

[复制链接]
15271953841 发表于 2024-3-24 22:54:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
>>>class S(str):
    def __add__(self,other):           (self用于绑定对象,如果让两个字符相加不是拼接,而是字符数之和代码这么写)
        return len(self) + len(other)

>>>s1 = S("FishC")
>>>s2 = S("Python")
>>>s1+s2                           (两个字符串的总字符个数,只要重写对象的add方法,就可实现对加法运算的拦截,魔法方法的作用就是拦截)
11
>>>s1 + "Python"             (也是统计两个字符之和)
11
>>>"FishC" + s2               (得到字符的拼接结果)
'FishCPython'
加法操作得有两个对象参与才行,那么我们这里重写的add方法是属于加号前面这个对象的方法,还是属于加号后面这个对象的方法呢?(看上面两步)
从上面add魔法方法的原型可以看出:self是自己,也就是加号左边的对象,other对象是指别人,就是加号右边的对象,所以s1+s2其实相当于s1.__add__(s2)
>>>s1.__add__(s2)
11
>>>s2.__add__(s1)
11
>>>s2+s1
11
>>>s2 + "FishC"
11
>>>"Python" + s1
'PythonFishC'

二、__radd__() 方法调用前提
当两个对象相加的时候,如果左侧的对象和右侧的对象不同类型,并且左侧的对象没有定义__add__()方法,或者其__add__()返回NotImplemented,那么Python就会去右侧对象中去查找是否有__radd__()方法的定义。
>>>class S1(str):
    def __add__(self,other):
        return NotImplemented

   
>>>class S2(str):
    def __radd__(self,other):
        return len(self) + len(other)

   
>>>s1 = S1("Apple")
>>>s2 = S2("Banana")
>>>s1 + s2
11
这里能够成功调用到s2的__radd__方法,首先是因为s2实现了__radd__方法,其实s1和s2两个是基于不同类的对象,再有一个条件就是s1里必须不能实现add方法,不然的话还是会优先去执行左侧对象的add方法,这里我们的add方法返回这个NotImplemented,含义就是明确表示这个方法未实现,如果我们s1不写这个方法,也是没问题的,也是可以的,其实魔法方法也是如法炮制,课后多练习。

三、增强赋值运算(运算兼赋值的操作)s1 += s2相当于s1 = s1.__iadd__(s2)
>>>class S1(str):
    def __iadd__(self,other):
        return len(self) + len(other)

   
>>>s1 = S1("Apple")
>>>s1 += s2
>>>s1
11
>>>type(s1)
<class 'int'>             (发现这个对象变成了“int”类型,所以使用增强赋值运算一定要先想清楚,不要一不小心,把自己的对象搞掉了)
>>>s2 += s2        (如果增强赋值运算符的左侧对象没有实现相应的魔法方法,比如说“+=”左侧的这个对象没有实现iadd的方法,Python就会退而求其次,使用相应的add方法或radd方法来替代,比如说s2这个对象看上面,s2这个对象没有实现iadd这个方法,但它有一个radd方法,s2 += s2变成s2是2个BananaBanana加到一块了。考一考大家,这里s2 += s2,不应该是去计算两者的字符串总个数吗?毕竟再s2里面它有去定义这个radd吗?对吧?radd就是len(self) + len(other),得到的应该是两个字符串的总字符个数呀?那这个在这却不生效,加出来的结果却是两BananaBanana的拼接呢?
因为要成功调用radd的方法,是要有条件的,首先它们两个要基于不同的类,这里s2 += s2,s2和s2都是相同的类,所以它自然不会去调用radd的方法,而是去它的祖宗,它的str这个父类里面去查找add方法得到就是字符串的拼接(易错))
>>>s2
'BananaBanana'
>>>type(s2)              (type(s2)它变成了str)
<class 'str'>

四、最后魔法方法并不仅仅只是能够拦截运算符而已,它连发生在对象的内置函数也能够多拦截的哦,比如说这个__int__函数,可以轻松将中文转化为整数的对象。
class ZH_INT:
    def __init__(self,num):
        self.num = num
    def __int__(self):
        try:
            return int(self.num)
        except ValueError:
            zh ={"零":0,"一":1,"二":2,"三":3,"四":4,"五":5,"六":6,"七":7,"八":8,"九":9,
                 "壹":1,"贰":2,"叁":3,"肆":4,"伍":5,"陆":6,"柒":7,"捌":8,"玖":9,}
            result = 0
            for each in self.num:
                if each in zh:
                    result += zh[each]
                else:
                    result += int(each)
                result *= 10
            return result // 10

        
n = ZH_INT("520")
int(n)
520
n = ZH_INT(3.14)
int(n)
3
n = ZH_INT("伍贰零")
int(n)
520
n = ZH_INT("五贰零1314")
int(n)
5201314

客服热线
400-1234-888 周一至周日:09:00 - 21:00
公司地址:襄阳市樊城区长虹路现代城5号楼188

创客帮MAKER.BAND青少年创客创意社区是一个融教育、科技、体育资讯为一体的综合服务平台,专注于教育创新、专注于科技体育、专注于教育资讯。

Powered by Discuz! X3.4 © 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表