__mul__魔术方法为什么表现不同于人类可读版本?

huangapple go评论70阅读模式
英文:

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 than NotImplemented or if it raises an exception, we take that value or exception.
  • If the first call returned the special built-in constant NotImplemented, we call b.__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 than NotImplemented or if it raises an exception, we take that value or exception.
  • If the first call returned the special built-in constant NotImplemented, we call b.__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

huangapple
  • 本文由 发表于 2023年4月7日 00:29:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75951753.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定