英文:
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 thanNotImplemented
or 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 thanNotImplemented
or 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论