__rmul__在什么情况下被调用?

说我有一个清单l。在什么情况下会呼叫l.__rmul__(self, other)

我基本上理解了文档,但是我也想看到一个示例来毫无疑问地阐明其用法。

porgarmingduod asked 2020-07-11T17:19:20Z
2个解决方案
110 votes

当Python尝试将两个对象相乘时,它首先尝试调用左对象的__mul__()方法。 如果左对象没有TypeError方法(或者该方法返回NotImplemented,表明它不适用于所讨论的右操作数),则Python想要知道右对象是否可以进行乘法。 如果右边的操作数与左边的操作数类型相同,Python就会知道它不能,因为如果左边的对象不能做到这一点,那么相同类型的另一个对象当然也不能。

但是,如果两个对象的类型不同,Python则值得一试。 但是,如果操作不是可交换的,则需要某种方式告诉正确的对象它是操作中的正确对象。 (当然,乘法不是全部运算符,在任何情况下都不总是使用__mul__()进行乘法!)因此它调用TypeError而不是NotImplemented

例如,请考虑以下两个语句:

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

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

现在我们可以看到__mul__()允许将所有字符串的特殊乘法行为包含在TypeError类中,这样其他类型(例如整数)无需了解任何有关字符串的知识即可将它们相乘。 从现在开始一百年后(假设Python仍在使用中),即使NotImplemented类一个多世纪以来一无所知,您仍可以定义一个可以按任一顺序乘以整数的新类型。

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


kindall answered 2020-07-11T17:20:04Z
9 votes

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

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将是带有val = 24Bar,但是对obj2的分配会产生错误,因为Bar没有__mul__并且Foo没有__rmul__

我希望这足够清楚。

Eli Bendersky answered 2020-07-11T17:20:35Z
translate from https://stackoverflow.com:/questions/5181320/under-what-circumstances-are-rmul-called