魔术方法和熊猫继承的Python设计模式

时间:2018-02-07 23:39:26

标签: python inheritance design-patterns

所以我基本上把这个问题提出了一些建议

我有几个类基本上做了一些pandas操作并返回一个数据帧。但是这些数据帧需要对某些滤波器选项进行加法和减法。我打算编写一个类来覆盖 __ add __ __ sub __ 方法,以便我的代码添加或减去这些数据帧,从而实现这些过滤器。以下是基本结构

import ArithOperation
class A:
  def dataA(self, filenameA):
    dfa = pd.read_excel(filenameA)
    return ArithOperation(dfA)

class B:
  def dataB(self, filenameB):
    dfb = pd.read_excel(filenameB)
    return ArithOperation(dfB)

dfA和dfB这里是pandas数据帧。

class ArithOperation:
  def __init__(self, df):
     self.df = df
  def __add__(self, other):
     # here the filtering and manual addition is done
     return ArithOperation(sumdf)
  def __sub__(self, other):
     # here the filtering and manual subtraction is done
     return ArithOperation(deltadf)

基本上我按以下计算

dfa = A().dataA()
dfb = B().dataB()

sumdf = dfa+dfb
deltadf = dfa-dfb

但是如何使 sumdf deltadf 也具有默认的数据帧功能。我知道我应该将数据帧类继承到 ArithOperation ,但我很困惑并且在很多地方实例化 ArithOperation()时感到有点不舒服。

  1. 这个问题有更好的设计模式吗?
  2. 在ArithOperation上继承哪个类,以便在ArithOperation对象上也拥有所有pandas数据帧函数?

1 个答案:

答案 0 :(得分:0)

在我看来,您希望自定义现有类型的行为(在这种情况下是数据框,但它可以是任何类型)。通常我们想要将某些行为改为另一种行为,或者我们想要扩展该行为,或者我们想要同时执行这两种行为。当我说行为思考方法时。)

您还可以选择has-a方法(即包装对象,通过创建一个新类,其对象包含对原始对象的引用。这样,您可以创建几个新的,不同的或类似的方法来创建新的通过使用存储的引用调用原始方法,最终使用一些现有的东西。这样你就可以将原始的类接口调整到另一个。这就是一个包装模式(或适配器模式)。

这就是你所做的。但是你面临一个问题:你如何接受原始课程的所有可能方法?你将不得不重写所有可能的方法(不是实际的),只是将它们委托给原始类,或者你找到一种方法来委托它们除了你重写的几个。我不会介绍这最后一种可能性,因为你可以随意使用继承,这使得这样的事情非常简单。

只需从原始类继承,您就可以创建与父类具有相同行为的对象。如果您需要新的数据成员,请覆盖__init__并添加这些成员,但不要忘记调用父类__init__,否则该对象将无法正确初始化。这就是您使用super().__init__()的地方,如下所述。如果要添加新方法,只需将常用的def添加到子类中。如果要扩展existant方法,请按照__init__方法的描述进行操作。如果你想完全覆盖一个方法,只需使用与original.method相同名称的def编写你的版本,它将完全替换原始版本。

因此,在您的情况下,您希望从dataframe类继承,您必须选择是否需要自定义__init__。如果您需要定义一个,但不要忘记在其中调用父项的原始。然后定义您的自定义方法,例如新的__add____sub__,替换或扩展原始方法(使用相同的技术)。 小心不要定义您认为是新的方法,但实际上存在于原始类中,因为它们将被覆盖。这是继承的一个小小的不便,特别是如果原始具有许多方法的接口。

使用super()扩展父类的行为

class A:
    pass # has some original __init__

class B(A): # B inherits A
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs) # preserves parent initialization, passing the same received arguments. If you don't do this parent __init__ will be overrided, not initialising parent object properly.
        # add your custom code
        pass

super()的问题在于它解决了在使用多重继承(从多个类继承)时出现的一些问题,在确定应该调用哪个parent方法时,如果你有几个具有相同的命名方法;建议在子类中使用SomeParentClass.method()调用父方法。

此外,如果您因为需要而对类型进行子类化,那么您不应该害怕在任何地方使用它,如您所说。确保你有充分的理由自定义它(所以想想是否适合数据帧,或者是否有另一种更简单的方法来实现相同的目标而不这样做;不能在这里建议你,我没有大熊猫的经验) ,然后用它代替原来的类。