首页 > 解决方案 > 如何将基于函数的数据管道转换为 OOP?

问题描述

我正在做一些数据处理并建立了几个管道,每个管道都包含多个函数,这些函数在每个步骤中都可以广泛地修改字典。由于不同的管道对相同的数据进行操作并具有相似的功能,因此我一直在尝试将其转换为更面向 OOP 的结构。然而,在我开始之前,我一直在打结。

采取以下简化示例:

for f in foos:
    y = extract_y_info(f)
    z = extract_z_info(f)
    *some code that does something with y and z*
    
def extract_y_info(f):
    return *some code that extracts y info from f*

def extract_z_info(f):
    return *some code that extracts z info from f*

对我来说,似乎有几种方法可以将其转移到 OOP 结构中。第一个与逐个函数的方法非常相似。

class foo():
    def __init__(self, x):
        self.x = x

    def extract_y_info(self):
        return *some code that extracts y info from self.x*

    def extract_z_info(self):
        return *some code that extracts z info from self.x*

for f in foo_instances:
    y = b.extract_y_info()
    z = b.extract_z_info()
    *some code that does something with y and z*

另一个选项是修改类的实例:

class foo():
    def __init__(self, x):
        self.x = x

    def extract_y_info(self):
        self.y = *some code that extracts y info from self.x*

    def extract_z_info(self):
        self.z = *some code that extracts z info from self.x*

for f in foo_instances:
    f.extract_y_info()
    f.extract_z_info()
    *some code that does something with f.y and f.z*

这些选项中的任何一个是否比另一个更好?有没有更好的第三种方式?

标签: pythonoop

解决方案


这实际上取决于您的整体设计是什么,您希望您的实例在任何给定时间处于什么状态以及您如何处理它(换句话说,y属性本身的存在是否意味着,但是......前者似乎通常更安全我。你调用并得到一个值,你不必跟踪,我是否调用了方法以及这个或那个属性处于什么状态?但请注意,你真的应该在构造函数中定义实例属性,否则访问可能不仅令人惊讶,而且是致命的(AttributeError)。

现在一个巧妙的解决方案解决了上述一些问题,并且可能适合您在这里似乎正在做的访问值的操作,这可能是一个property,它本质上允许您访问方法返回的值,就好像它是一个实例属性一样:

class foo():
    def __init__(self, x):
        self.x = x

    def extract_y_info(self):
        return #some code that extracts y info from self.x

    y = property(extract_y_info)     

for f in foo_instances:
    print(f"value of f.y = {f.y}")

或者你可以使用propertyas 方法装饰器来做同样的事情:

    @property
    def y(self):
        return #some code that extracts y info from self.x

如果获取y成本很高,并且它的价值在实例的整个生命周期内不会改变,那么从 Python 3.8 开始,您也可以使用cached_property.


推荐阅读