英文:
Why does the __mul__ magic method behave differently than the human-readable version?
问题
I've been explaining Python magic functions to someone and I naturally showed these examples:
In [1]: str("v").mul(5)
Out[1]: 'vvvvv'
In [2]: "v" * 5
Out[2]: 'vvvvv'
But then I moved on to how transitivity is implemented and tried also this example that failed:
In [3]: 5 * "v"
Out[3]: 'vvvvv'
In [4]: int(5).mul("v")
Out[4]: NotImplemented
I was not able to explain why this last one did not work. Could you help me?
英文:
I've been explaining Python magic functions to someone and I naturally showed these examples:
In [1]: str("v").__mul__(5)
Out[1]: 'vvvvv'
In [2]: "v" * 5
Out[2]: 'vvvvv'
But then I moved on to how transitivity is implemented and tried also this example that failed:
In [3]: 5 * "v"
Out[3]: 'vvvvv'
In [4]: int(5).__mul__("v")
Out[4]: NotImplemented
I was not able to explain why this last one did not work. Could you help me?
答案1
得分: 3
这是因为 __mul__ 只处理运算符在左侧的情况。 int.__mul__ 不处理 str,只有 str.__mul__ 处理 int。 对于 5 * 'v' 的实际 * 运算符,首先询问 int.__mul__ 是否知道如何处理 str,当它返回 NotImplemented 时,询问 str.__rmul__(注意 r,代表“反射”)是否知道如何在左侧为 int 的情况下处理运算符的右侧;它知道,所以得到预期的结果。
英文:
It's because __mul__ only handles the case where the operator is on the left side of the operator. int.__mul__ doesn't handle str, only str.__mul__ handles int. The actual * operator for 5 * 'v' first asks int.__mul__ if it knows how to handle a str, and when it returns NotImplemented, it asks str.__rmul__ (note the r, for "reflected") if it knows how to handle being on the right hand side of the operator when int is on the left; it does, so you get the expected result.
Some overly language lawyer quotes from the Python Data Model section on the forward and reverse binary operator overloading special methods:
> [__r*__] functions are only called if the left operand does not support the corresponding operation, and the operands are of different types. For instance, to evaluate the expression x - y, where y is an instance of a class that has an __rsub__() method, type(y).__rsub__(y, x) is called if type(x).__sub__(x, y) returns NotImplemented.
答案2
得分: 3
The * binary operator doesn't just call __mul__. Specifically, a * b does the following:
- First, it calls
a.__mul__(b). If that function returns anything other thanNotImplementedor if it raises an exception, we take that value or exception. - If the first call returned the special built-in constant
NotImplemented, we callb.__rmul__(a)(note that the arguments are reversed).
So if you call "v".__rmul__(5), you'll get the result you want.
If your goal is to have a function that behaves identically to the star operator, you can do it with a lambda (lambda x, y: x * y), or you can import operator.mul。
英文:
The * binary operator doesn't just call __mul__. Specifically, a * b does the following:
- First, it calls
a.__mul__(b). If that function returns anything other thanNotImplementedor if it raises an exception, we take that value or exception. - If the first call returned the special built-in constant
NotImplemented, we callb.__rmul__(a)(note that the arguments are reversed).
So if you call "v".__rmul__(5), you'll get the result you want.
If your goal is to have a function that behaves identically to the star operator, you can do it with a lambda (lambda x, y: x * y), or you can import operator.mul
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论