鱼C论坛

 找回密码
 立即注册
查看: 2698|回复: 9

[知识点备忘] 第066讲:类和对象(IX)

[复制链接]
发表于 2022-6-30 18:05:40 | 显示全部楼层 |阅读模式
购买主题 已有 25 人购买  本主题需向作者支付 5 鱼币 才能浏览
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-9-7 14:35:31 | 显示全部楼层
小甲鱼你好~
这节课程有个疑问,__radd__()方法调用的前提之一是左侧对象没有定义__add__方法,但是通过dir()函数获取左侧对象的信息,里面是有__add__方法的,且可以通过【左侧对象.__add__(other)】来调用其__add__()方法的,因此不太理解这‘左侧对象没有定义__add__方法’的点。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-4-7 05:17:29 | 显示全部楼层
Becoming_y 发表于 2022-9-7 14:35
小甲鱼你好~
这节课程有个疑问,__radd__()方法调用的前提之一是左侧对象没有定义__add__方法,但是通过d ...


简单的说,因为内置的 __add__() 不算,自己定义的才算。

下面是详细解答:

对于 Python 中的二元操作符(如 +、-、* 等),它们的执行顺序是由左到右的,也就是说,在表达式 a + b 中,首先会调用 a 对象的 add 方法,然后将 b 作为参数传入该方法中。

当左侧对象(即 a)没有定义 __add__() 方法时,Python 会尝试调用右侧对象(即 b)的 __radd__() 方法。如果右侧对象也没有定义 __radd__() 方法,Python 会抛出 TypeError 异常。

所以,当你在左侧对象上调用 dir() 方法时,会列出该对象拥有的所有属性和方法,包括内置的 __add__() 方法。但是,如果该对象没有自定义自己的 __add__() 方法,Python 会自动调用右侧对象的 __radd__() 方法。

因此,当你在实现 __radd__() 方法时,应该确保左侧对象没有定义 __add__()方法,否则 __add__() 方法会被优先调用,而不会调用 __radd__() 方法。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2022-9-29 09:53:35 | 显示全部楼层
运算相关的魔法方法数量繁多,应有尽有!通过重写这些魔法方法,可以实现对相应运算的拦截,随心所欲!二元的运算魔法方法分为算术运算、反算术运算和增强赋值运算三类,三类方法一一对应,只不过反算数运算的魔法方法由运算符右侧的对象触发(当两侧对象不同类型,且左侧对象未定义相应算术运算方法或其返回NotImplemented时),增强赋值运算的魔法方法具有运算兼赋值的功能,会修改对象自身;如果增强赋值运算符左侧的对象没有实现相应方法,Python则会退而求其次,使用相应的算术运算或反算术运算方法来替代。最后,魔法方法并不仅仅能拦截运算符,甚至能拦截发生在对象的内置函数,如重写__int__()方法使int()也能将汉字转化为相应的整数,做法是在捕获ValueError异常后利用字典实现映射,巧妙又实用!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2022-9-29 09:59:16 | 显示全部楼层
Becoming_y 发表于 2022-9-7 14:35
小甲鱼你好~
这节课程有个疑问,__radd__()方法调用的前提之一是左侧对象没有定义__add__方法,但是通过d ...

“左侧对象没有定义__add__()方法”和“左侧对象的__add__()方法返回NotImplemented”二者只要满足其一,并且两侧对象不同类型,就会执行右侧对象的__radd__()方法。视频中演示的例子左侧对象虽有__add__()方法,但其返回NotImplemented,故依然会调用右侧对象的__radd__()方法。
@小甲鱼
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-2 10:40:35 | 显示全部楼层
为啥 result += zh[each] 这一步不会实现数字相加,而是实现类似于拼接的操作呢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-17 14:39:08 | 显示全部楼层
Muadhnait 发表于 2022-11-2 10:40
为啥 result += zh[each] 这一步不会实现数字相加,而是实现类似于拼接的操作呢

在for循环里,每一位数有result *= 10 提升位数,五->5->50,下一步+2就变成了52,循环结束变成52013140,
再用 result  // 10 去掉最后加上去的一位0,得到想要的结果。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-6 15:48:02 | 显示全部楼层
本帖最后由 Ensoleile 于 2023-1-10 00:34 编辑

运算相关的魔法方法(上)P163
class S(str):
    def __add__(self, other):
        return len(self) + len(other)

s1 = S('FishC')
s2 = S('python')
print(s1 + s2)
#11
print('FishC' + s2)#FishCpython
print(s1 + 'python')#11
#从__add__()魔法方法的原型也可以看出端倪,加号左边的对象是self指自己,右边对象other指别人,s1 + s2相当于s1.__add__(s2)

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

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

s1 = S1('apple')
s2 = S2('banana')
print(s1 + s2)#11
#成功调用s2的__radd__()方法。①s1和s2两个是基于不同类的对象,②且s1里不能实现__add__()方法,否则还是会优先执行左侧对象的__add__()方法(如果s1不写__add__()方法也可以实现)

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

s1 = S1('apple')
s1 += s2
print(s1, type(s1), sep='   ')#11   <class 'int'>
#如果增强赋值运算符的左侧对象没有实现相应的魔法方法,如+=左侧对象没有实现__iadd__()方法,那么python就会退而求其次使用__add__()方法和__radd__()方法来替代
print(s2, type(s2), sep='***')#banana***<class '__main__.S2'>
s2 += s2
print(s2, type(s2), sep='***')#bananabanana***<class 'str'>
#+=两侧都是s2为同一类,所以不能调用__radd__()方法,而是去父类str中查找__add__()方法

#魔法方法不仅能拦截运算符,也可以拦截发生在对象的内置函数
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')
print(int(n))#520
n = ZH_INT(3.14)
print(int(n))#3
n = ZH_INT('五贰零')
print(int(n))#520
n = ZH_INT('五贰零1314')
print(int(n))#5201314
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-4-8 01:16:26 | 显示全部楼层
本帖最后由 dearfish 于 2023-4-9 00:07 编辑

要多琢磨,多领悟
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-4-17 22:05:03 | 显示全部楼层
循环语句,乘10又除以10这块不理解的,可以在代码里添加print(result)语句,看看循环执行过程,就很容易理解了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 09:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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