我用Python 3编写的程序有许多地方,它以一个(非常大的)类似于表的数字数据结构开始,并在某些算法。 (这个算法在每个地方都不一样)。将一个表“增长”的命令式算法转换为纯函数
我试图将它转化为纯粹的函数式方法,因为我遇到了命令式方法的问题(难以重用,难以记忆临时步骤,很难实现“懒惰”计算,由于依赖状态而容易出错等)。
Table
该类实现为词典的词典:外部词典包含行,索引为row_id
;内部包含一行内的值,由column_title
索引。该表的方法很简单:
# return the value at the specified row_id, column_title
get_value(self, row_id, column_title)
# return the inner dictionary representing row given by row_id
get_row(self, row_id)
# add a column new_column_title, defined by func
# func signature must be: take a row and return a value
add_column(self, new_column_title, func)
到现在为止,我只是简单地添加列到原始表,以及每个函数把整个表作为参数。随着我转向纯函数,我必须使所有参数不变。所以,初始表变得不可变。任何额外的列将被创建为独立列,并只传递给那些需要它们的函数。一个典型的函数将采用初始表和几个已经创建的列,并返回一个新列。
我遇到的问题是如何实现独立列(Column
)?
我可以让他们每一个字典,但它似乎非常昂贵。事实上,如果我需要对每个逻辑行中的10个字段执行操作,则需要执行10次字典查找。最重要的是,每列将包含键和值,使其大小加倍。
我可以使Column
成为一个简单的列表,并在其中存储对从row_id到数组索引的映射的引用。好处是这个映射可以在对应于同一个初始表的所有列之间共享,并且一次只查找一次,它适用于所有列。但是这是否会产生其他问题?
如果我这样做,我可以走得更远,并实际存储在初始表本身的映射?我可以将Column
对象的引用放回到创建它们的初始表中吗?它与我想象的功能性方法的工作方式似乎有很大的不同,但我不能看出它会造成什么问题,因为一切都是不变的。
通常情况下,函数方法对保持参数的返回值中的某个参数感到皱眉吗?它似乎不会破坏任何东西(如优化或懒惰评估),因为无论如何这个论点都是已知的。但也许我错过了一些东西。
你有没有想过使用Numpy数组?这听起来就像Numpy设计要处理的事情:访问特定的列或行并将它们作为参数传递很容易,而且非常快速,特别是对于纯数字操作。 –
'numpy.array'会很好; 'pandas.DataFrame'甚至更好。但不幸的是,由于我列出的原因,我真的想转向纯粹的功能。这需要不变性,所以我不能通过附加新计算的列来扩展原始表。 – max
您仍然可以编写接受并返回任何维度(单列,整个表......)的Numpy数组的函数,而不会偏离函数式样。国际海事组织,'ndarray'类型的可变性既不存在也不存在;你只需要确保你的功能没有任何副作用。如果你不想使用可变性,那就这样吧。 –