为什么我们需要三种不同的方式来进行大熊猫活动?

时间:2019-04-19 04:11:43

标签: python pandas dataframe

为什么我们需要三种操作方式?

(我以乘法为例)

第一种方式:

df['a'] * 5

第二种方式:

df['a'].mul(5)

第三种方式:

df['a'].__mul__(5)

不仅仅是两个,就不需要mul,我想知道它是否可以像普通方式一样,像整数

第一种方式:

3 * 5

第二种方式:

(3).__mul__(5)

但是在一个整数的基础上:

(3).mul(5)

会休息。

我很好奇,为什么我们在熊猫中需要这么多东西,加,减和除法也是一样。

3 个答案:

答案 0 :(得分:3)

*mul做相同的事情,但是__mul__不同。

*mul在委派给__mul__之前执行一些检查。您应该了解两件事。

  1. NotImplemented

在无法处理其他操作数的情况下,类的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所做的某些检查。

  1. 派生的类运算符处理

如果您尝试执行类似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甚至不会先看 ;它会立即委派给Derived.__rmul__

为完整起见,在*的上下文中,mulpandas之间有一个区别:mul是一个函数,并且因此可以在变量中传递并独立使用。例如:

import pandas as pd

pandas_mul = pd.DataFrame.mul
pandas_mul(pd.DataFrame([[1]]), pd.DataFrame([[2]]))

另一方面,这将失败:

*(pd.DataFrame([[1]]), pd.DataFrame([[2]]))

答案 1 :(得分:1)

在底层python中,“魔术方法” __mul__和运算符*都是相同的(*只是调用__mul__),正如您所指出的那样是Python稳定处理事物的方式。另一种方法mul是一种可用于映射的方法(使用map),例如,避免使用lambda x, y: x*mul。 是的,您仍然可以使用__mul__,但是通常这些方法(__x__的目的不是用作常规功能,而简单的mul可以使代码更清晰。

因此,您并不是真的“需要”它,但是拥有和使用它很好。

答案 2 :(得分:1)

首先,永远不要使用第三种方式(df['a'].__mul__(5)),因为它是Python类调用的内部方法。通常,用户不会触摸任何“笨拙”的方法。

关于其他两种方式,第一种是显而易见的。你只是乘以东西。这是标准数学。

第二种方法变得更加有趣。我如何使用该方法的一个示例是当您要应用的函数是变量时。

例如:

def pandas_math(series, func, val):
    return getattr(series, func)(val)

pandas_math(df['a'], 'mul', 5)将得到与df['a'].mul(5)相同的结果,但是现在您可以将mul作为变量或要使用的任何其他函数传递。比对所有符号进行硬编码要容易得多。