这节课程有个疑问,__radd__()方法调用的前提之一是左侧对象没有定义__add__方法,但是通过dir()函数获取左侧对象的信息,里面是有__add__方法的,且可以通过【左侧对象.__add__(other)】来调用其__add__()方法的,因此不太理解这‘左侧对象没有定义__add__方法’的点。 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__() 方法。
运算相关的魔法方法数量繁多,应有尽有!通过重写这些魔法方法,可以实现对相应运算的拦截,随心所欲!二元的运算魔法方法分为算术运算、反算术运算和增强赋值运算三类,三类方法一一对应,只不过反算数运算的魔法方法由运算符右侧的对象触发(当两侧对象不同类型,且左侧对象未定义相应算术运算方法或其返回NotImplemented时),增强赋值运算的魔法方法具有运算兼赋值的功能,会修改对象自身;如果增强赋值运算符左侧的对象没有实现相应方法,Python则会退而求其次,使用相应的算术运算或反算术运算方法来替代。最后,魔法方法并不仅仅能拦截运算符,甚至能拦截发生在对象的内置函数,如重写__int__()方法使int()也能将汉字转化为相应的整数,做法是在捕获ValueError异常后利用字典实现映射,巧妙又实用! Becoming_y 发表于 2022-9-7 14:35
小甲鱼你好~
这节课程有个疑问,__radd__()方法调用的前提之一是左侧对象没有定义__add__方法,但是通过d ...
“左侧对象没有定义__add__()方法”和“左侧对象的__add__()方法返回NotImplemented”二者只要满足其一,并且两侧对象不同类型,就会执行右侧对象的__radd__()方法。视频中演示的例子左侧对象虽有__add__()方法,但其返回NotImplemented,故依然会调用右侧对象的__radd__()方法。
@小甲鱼 为啥 result += zh 这一步不会实现数字相加,而是实现类似于拼接的操作呢{:5_94:}{:10_269:} Muadhnait 发表于 2022-11-2 10:40
为啥 result += zh 这一步不会实现数字相加,而是实现类似于拼接的操作呢
在for循环里,每一位数有result *= 10 提升位数,五->5->50,下一步+2就变成了52,循环结束变成52013140,
再用 result// 10 去掉最后加上去的一位0,得到想要的结果。 本帖最后由 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
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 本帖最后由 dearfish 于 2023-4-9 00:07 编辑
要多琢磨,多领悟 循环语句,乘10又除以10这块不理解的,可以在代码里添加print(result)语句,看看循环执行过程,就很容易理解了。
页:
[1]