在什么情况下__rmul__被称为?

时间:2011-03-03 13:28:20

标签: python operators

说我有一个列表l。在什么情况下调用l.__rmul__(self, other)

我基本上理解了文档,但我还希望看到一个例子来澄清其用法,毫无疑问。

3 个答案:

答案 0 :(得分:105)

当Python尝试将两个对象相乘时,它首先尝试调用左对象的__mul__()方法。如果左对象没有__mul__()方法(或者方法返回NotImplemented,表明它不能使用正确的操作数),那么Python想要知道正确的对象是否可以做乘法。如果右操作数与左边的操作数相同,那么Python知道它不能,因为如果左边的对象不能这样做,那么同一类型的另一个对象当然也不能。

如果这两个对象是不同的类型,Python认为它值得一试。但是,如果操作不可交换,它需要某种方式告诉正确的对象操作中的正确对象。 (乘法当然是,但并非所有运算符都是,并且在任何情况下*并不总是用于乘法!)因此它调用__rmul__()而不是__mul__()

例如,请考虑以下两个陈述:

print "nom" * 3
print 3 * "nom"

在第一种情况下,Python调用字符串的__mul__()方法。字符串知道如何将自身乘以整数,所以一切都很好。在第二种情况下,整数不知道如何将自身乘以字符串,因此其__mul()__返回NotImplemented并调用字符串__rmul()__。它知道该怎么做,你得到的结果与第一种情况相同。

现在我们可以看到__rmul()__允许所有字符串的特殊乘法行为包含在str类中,这样其他类型(如整数)就可以不需要知道关于字符串的任何信息,以便能够乘以它们。从现在起一百年后(假设Python仍然在使用中)你将能够定义一个新类型,它可以按任意顺序乘以一个整数,即使int类已经知道它不超过一个世纪。

顺便说一句,字符串类的__mul__()在某些Python版本中有一个错误。如果它不知道如何将自身乘以一个对象,它会引发TypeError而不是返回NotImplemented。这意味着即使用户定义的类型具有__rmul__()方法,也不能将字符串乘以用户定义的类型,因为字符串永远不会让它有机会。用户定义的类型必须先行(例如Foo() * 'bar'而不是'bar' * Foo()),以便调用其__mul__()。他们似乎已经在Python 2.7中解决了这个问题(我也在Python 3.2中测试过它),但Python 2.6.6有错误。


答案 1 :(得分:9)

二元运算符本质上有两个操作数。每个操作数可以位于运算符的左侧或右侧。当您为某种类型的操作符重载时,您可以指定操作符的哪一侧完成重载。在两个不同类型的操作数上调用运算符时,这很有用。这是一个例子:

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__

我希望这很清楚。

答案 2 :(得分:0)

{__mul__()是点积的情况,并且点积的结果应该是标量或仅是数字,即__mul__()会导致点积乘法,如x1*x2+y1*y2。在__rmul__()中,结果是一个带有x = x1*x2y = y1*y2的点。