回答
当Python试图乘以两个对象时,它首先尝试调用左对象的方法__mul__()
。如果左对象没有__mul__()
方法(或者方法返回NotImpemented
,表明它不适用于所讨论的右操作数),那么Python想知道正确的对象是否可以执行乘法。如果右操作数与左操作数是相同的类型,Python知道它不能,因为如果左对象不能这样做,另一个同类型的对象肯定不能。
但是,如果这两个对象是不同的类型,Python会认为它值得一试。然而,在操作不可交换的情况下,它需要某种方式来告诉正确的对象,它在操作中是正确的对象。 (当然,乘法是,但不是所有的操作符都是,在任何情况下*
并不总是用于乘法!)所以它调用__rmul__()
而不是__mul__()
。
作为一个例子,考虑以下两个语句:
print "nom" * 3
print 3 * "nom"
在第一种情况下,Python会自动调用该字符串的__mul__()
方法。字符串知道如何乘以一个整数本身,所以一切都很好。在第二种情况下,整数不知道如何乘以一个字符串,所以它的__mul()__
返回NotImplemented
,并调用字符串的__rmul()__
。它知道该怎么做,并且获得与第一种情况相同的结果。
现在我们可以看到,__rmul()__
允许字符串的特殊繁殖行为的所有被包含在str
类等其他类型(如整数)不需要知道字符串什么能够繁殖被他们。从现在开始的一百年(假设Python仍在使用中),您将能够定义一种新的类型,它可以按任意顺序乘以一个整数,即使类已经超过一个世纪都不知道它。
顺便说一句,字符串类的__mul__()
在某些版本的Python中有一个错误。如果它不知道如何乘以一个对象,它将产生一个TypeError
而不是返回NotImplemented
。这意味着即使用户定义的类型具有__rmul__()
方法,也不能用字符串乘以用户定义的类型,因为字符串决不会让它有机会。用户定义的类型必须先执行(例如Foo() * 'bar'
而不是'bar' * Foo()
),因此调用其__mul__()
。他们似乎已经在Python 2.7中解决了这个问题(我也在Python 3.2中对它进行了测试),但是Python 2.6.6有这个bug。
二元运算符本质上有两个操作数。每个操作数可能在操作符的左侧或右侧。当您为某种类型重载操作符时,可以指定操作符的哪一侧执行重载操作。当在不同类型的两个操作数上调用操作符时,这非常有用。这里有一个例子:
class Foo(object):
def __init__(self, val):
self.val = val
def __str__(self):
return "Foo [%s]" % self.val
class Bar(object):
def __init__(self, val):
self.val = val
def __rmul__(self, other):
return Bar(self.val * other.val)
def __str__(self):
return "Bar [%s]" % self.val
f = Foo(4)
b = Bar(6)
obj = f * b # Bar [24]
obj2 = b * f # ERROR
这里,obj
将是一个Bar
与val = 24
,但分配给obj2
产生一个错误,因为Bar
没有__mul__
和Foo
没有__rmul__
。
我希望这已经够清楚了。
- 1. 在什么情况下调用Application_EndRequest,但是Application_BeginRequest未被调用?
- 2. 为什么在以下情况下不会调用“onPause”?
- 3. 在什么情况下,该应用程序:didFinishLaunchingWithOptions:被调用?
- 4. 在UIView实现中,在什么情况下drawRect被调用?
- 5. 如何在使用情况下在什么情况下使用tsql?
- 6. 在什么情况下调用Parse HTML事件?
- 7. 在什么情况下不会调用Sybase触发器?
- 8. 在什么情况下会调用iOS系统推送通知?
- 9. 在什么情况下C++析构函数不会被调用?
- 10. 在什么情况下,我们需要调用GC.Collect两次
- 11. 什么情况下**会有用?
- 12. TextToSpeech.isSpeaking()在什么情况下返回true?
- 13. SiteLogoUrl在什么情况下工作?
- 14. sched_yield在这种情况下做什么?
- 15. .map()在这种情况下做什么?
- 16. imul在什么情况下写入edx?
- 17. 在什么情况下System.Collections.ArrayList.Add抛出IndexOutOfRangeException?
- 18. Rails after_filter在什么情况下运行?
- 19. 什么是在这种情况下
- 20. *在这种情况下做什么?:
- 21. 什么是在这种情况下
- 22. 在什么情况下document.open()返回null?
- 23. ConcurrentBag.TryTake()在什么情况下会失败?
- 24. 为什么在这种情况下
- 25. 在什么情况下glGenBuffers/glGenBuffersARB失败?
- 26. 在什么情况下会http.ListenAndServe返回
- 27. 在什么情况/情况下,dynamic_cast <>可能会失败?
- 28. 为什么NaN有用,在什么情况下
- 29. Rxjs:你想要什么情况下使用调度
- 30. 浏览器在什么情况下拒绝继续调用setInterval回调?
以前接受的答案没什么不对,但如果有人在将来出现在这里,他们可能想在顶部碰到这个答案,所以我会接受它。 – porgarmingduod 2011-03-03 15:51:59
++,优秀的答案 - 我学到了一些东西:) – 2011-03-03 17:18:17
kindall说:这可能是你已经接受了答案,但现在浪费了精力: 我想向你保证你的努力没有被浪费 - 我遇到了问题使向量代数中的__rmul__有用(用于向量的标量乘法)。你的解释足以说服我,在(标量)*(矢量)操作的情况下,__mul__方法应该以“raise NotImplementedError()”或“return Not Implemented”结束,以使调用进入__rmul__方法。感谢您的帮助! – user377367 2011-05-07 01:13:26