扩展现有第三方库的现有类的功能的最佳方法是什么?

2024-09-30 01:32:41 发布

您现在位置:Python中文网/ 问答频道 /正文

例如,我在代码中使用了很多pandas.DataFrames。这是一个非常大的类,有很多部分,并且它有一个非常函数化的API,在这里你可以把它的方法调用链接在一起。在

如果能够轻松地将功能添加到这个现有类中,同时仍然保持功能性的、流动的API,感觉会很好。在

我想把这个类转换成一些特定于领域的东西,这样可以删除很多在使用这个类时经常使用的特定于领域的样板代码。在

假设在我的梦里我能做这样的事情:

pandas.read_csv('sales.csv') \
    .filter(items=['one', 'three']) \
    .apply(myTransformationFunction) \
    .saveToHivePartition(tablename = 'sales', partitionColumn = 'four') \
    .join(pandas.read_csv('employees.csv')) \
    .filter(items=['one','three','five']) \
    .saveToHivePartition(tablename = 'EmployeeMetrics', partitionColumn = 'ten')

在本例中,saveToHivePartition是一个自定义方法,它做了大量工作,以原子方式将某些内容保存到HDFS的正确位置,然后将这些信息添加到配置单元元数据存储中。超级有用!在

显然,“简单”的答案是简单地创建一个独立的函数,我可以将DataFrame对象与我需要的其他参数一起传递到该函数中。每次我想执行保存时,我都需要将dataframe封装到一个变量中,然后将该变量传递到一个单独的函数中。没有比上面的例子更干净的了!在

所以接下来想到的是创建一些很酷的新的SuperDataFrame类,它是DataFrame的超集。这种方法的唯一问题是:如何构建它?我无法更改pandas.read_csv()以开始返回我的新类。我不能将基类强制转换为子类。我本可以。。。数据帧类的包装器?但我想,每当我想调用一个base DataFrame函数时,它必须是这样的:

^{pr2}$

我甚至不认为这是可行的,因为这假设每当pandas执行某个功能时,它会在适当的位置上使DataFrame发生突变,我很确定它甚至不会。在

有什么想法吗?还是这只是件坏事?在


Tags: csv方法函数代码功能apidataframepandas
2条回答

可以使用constructor-override properties确保pandas操作返回新类的实例。一个简单的例子:

class MyDF(pandas.DataFrame):
    @property
    def _constructor(self):
        return MyDF

    def myMethod(self):
        return "I am cool"

>>> d = MyDF([[1, 2, 3], [4, 5, 6], [7, 8, 9]], columns=["A", "B", "C"])
>>> d.filter(["A", "B"]).apply(lambda c: c**2).myMethod()
'I am cool'

当然,如果您还想处理Series,您还必须创建自己的Series子类,并可能定义custom data slots。在

也就是说,我不清楚你的例子是否真的值得这样做。您已经可以将方法调用链接到普通的数据帧上,因此,如果您只想保存一些中间阶段,则不必太麻烦:

^{pr2}$

(由于我在评论中提到的问题,我改变了过滤器的顺序。先过滤到较小的子集,然后再过滤到较大的子集是没有意义的;较大的子集稍后将不存在,因为其中一些已经被过滤掉了。)

仅仅是将东西写成方法链的能力本身并不是一种优势。我特别怀疑像你的.saveToHivePartition这样的链接方法,这些方法可能只是因为它们的副作用才被调用的。当方法以装配线的方式运行时,将它们链接起来是有意义的,每个方法都接受前一个方法的输入并将其修改为传递给下一个方法。只是返回一个对象并不能使代码更具可读性。在

另外,请注意,此解决方案是针对熊猫的。一般来说,如果某些库中的类创建另一个实例,则必须仔细设计该库,以允许以保留类之间关系的方式进行子类化。Pandas已经用我描述的构造函数重写机制完成了这项工作,但它并不总是那样,而且在此之前,很难完成您正在尝试的操作。在

一种方法是扩展DataFrame类。为了保持流畅的界面,您可以创建自己的custom.read_csv

def read_csv(file):
    dataframe = pandas.read_csv(file)
    return SuperDataFrame(dataframe)

首先调用该函数,其余函数调用保持原样。您只需将所需的函数添加到新的dataframe中。在

或者(python特定的hack),您可能可以将自己的函数直接导入到导入它的模块中的原始dataframe类中,但不要。。。在

相关问题 更多 >

    热门问题