为什么我们需要三种操作方式?
(我使用乘法作为例子)
第一种方式:
df['a'] * 5
第二种方式:
df['a'].mul(5)
第三种方式:
df['a'].__mul__(5)
不是两个就够了,不需要mul
,我想知道它是否可以像正常方式一样,像一个整数
第一种方式:
3 * 5
第二种方式:
(3).__mul__(5)
但是在 inetger 的常规基础上:
(3).mul(5)
会坏掉。
我只是好奇,为什么我们在 Pandas 中需要这么多东西,加法、减法和除法都是一样的。
最佳答案
*
和 mul
做同样的事情,但 __mul__
不同。
*
和 mul
在委托(delegate)给 __mul__
之前执行一些检查。有两件事您应该了解。
未实现
有一个特殊的单例值 NotImplemented
,在类的 __mul__
无法处理其他操作数的情况下,它会返回。然后,这会告诉 Python 尝试 __rmul__
。如果也失败,则会引发通用 TypeError
。如果你直接使用__mul__
,你不会得到这个逻辑。观察:
class TestClass:
def __mul__(self, other):
return NotImplemented
TestClass() * 1
输出:
TypeError: unsupported operand type(s) for *: 'TestClass' and 'int'
将其与此进行比较:
TestClass().__mul__(1)
输出:
NotImplemented
这就是为什么,一般来说,您应该避免直接调用 dunder(魔术)方法:您绕过了 Python 所做的某些检查。
- 派生类运算符处理
当您尝试执行诸如 Base() * Derived()
之类的操作时,其中 Derived
继承自 Base
,您会期望 Base.__mul__(Derived())
首先被调用。这可能会带来问题,因为 Derived.__mul__
更有可能知道如何处理此类情况。
因此,当您使用*
时,Python会检查右操作数的类型是否比左操作数的派生程度更高,如果是,则直接调用右操作数的__rmul__
方法。
观察:
class Base:
def __mul__(self, other):
print('base mul')
class Derived(Base):
def __rmul__(self, other):
print('derived rmul')
Base() * Derived()
输出:
derived rmul
请注意,即使 Base.__mul__
不返回 NotImplemented
并且可以清楚地处理 Derived
类型的对象,Python 甚至不先看;它立即委托(delegate)给 Derived.__rmul__
。
为了完整起见,在 pandas
的上下文中,*
和 mul
之间有一个区别:mul
是一个函数,因此可以在变量中传递并独立使用。例如:
import pandas as pd
pandas_mul = pd.DataFrame.mul
pandas_mul(pd.DataFrame([[1]]), pd.DataFrame([[2]]))
另一方面,这将会失败:
*(pd.DataFrame([[1]]), pd.DataFrame([[2]]))
关于python - 为什么我们需要三种不同的方式来操作 pandas?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55756505/