扁平优于嵌套" - 对数据和代码都是如此吗?
这篇问题让我思考:我们是否应该把“扁平化比嵌套更好”的原则应用到数据上,而不仅仅是代码?即使数据本身有一个“逻辑树结构”呢?
在这种情况下,我想这意味着用一个ID的列表来表示子节点,而不是实际的子节点列表,把所有节点放在一个单一的列表里:
[ {'id': 4, 'children': ()},
{'id': 2, 'children': (1, 7)},
{'id': 1, 'children': (6, 5)},
{'id': 6, 'children': ()},
{'id': 5, 'children': ()},
{'id': 7, 'children': (3,)},
{'id': 3, 'children': ()} ]
(我使用元组是因为我不想给自己太多修改对象的灵活性,直到这种灵活性证明是有用的并且可以清晰使用。无论如何,我在这里绝对不会用None
来代替空序列,因为那样会让逻辑变得复杂,而且“特殊情况并不够特殊”——在这里,它根本就不特殊。)
这样确实更简短,但树结构就变得不明显了。这是不是和“明确比隐含更好”相矛盾呢?
就我个人而言,我觉得“扁平化比嵌套更好”的适用性有限,远不是禅宗中最重要的方面。(当然,如果我不允许自己有一定的嵌套,我就无法做很多不错的函数式编程的事情。)我怀疑“嵌套”的问题在于,当你理解信息时需要切换上下文。我真的认为这个问题在遵循命令式逻辑时更明显,而在解析数据或函数式代码时就简单多了——在那种情况下,你可以更容易地给嵌套的部分起个名字,并把它的工作与外部上下文分开考虑。
你怎么看?
6 个回答
我们是否应该把“扁平比嵌套好”的原则也应用到数据上,而不仅仅是代码呢?
不应该。
即使数据有一个“逻辑树结构”呢?
这就是为什么“扁平比嵌套好”这个原则不适用于数据,只适用于代码。
...树结构变得不清晰。这是不是和“显式比隐式好”相矛盾呢?
这根本没法比较。“扁平树”是一种常见的SQL实现,因为SQL无法处理真正树形结构的无限递归。
把Python的哲学和数据结构设计拿来比较是没有意义的。这两者就像数字“2”和把一块奶酪分成“2”块一样,根本没法比。一个是事物,另一个是动作。
数据结构是事物。
Python描述的是动作。
这个问题完全是主观的。答案是:“这要看情况。”
这取决于你数据的主要用途。如果你经常需要引用嵌套结构,那么用这种方式表示数据是有道理的。如果你除了在构建嵌套结构时根本不使用平面结构,那为什么还要保留平面结构呢?
所谓的“平面”表示法是关系数据库模型的基础之一:每种类型的数据都存在于专门的表中,而这些数据之间的关系则放在不同的表里。这种方式很有用,但在代码中有时会比较难处理。另一方面,处理某种特定类型的所有数据则非常简单。
举个例子,如果我想找到你示例数据中id为2的记录的所有后代。如果数据已经是层级结构(也就是说,原生表示是“嵌套”结构),那么找到id为2的记录并遍历它的子记录、孙记录等就非常简单。
但是,如果原生表示是你展示的那种顺序结构,那么我就得遍历整个数据集来创建层级结构,然后再找到记录2及其子记录。
所以,正如我所说的,“这要看情况。”
我其实对这两种方式没有特别的偏好,主要是看哪个更适合具体的任务。
如果结构很重要,使用嵌套的方式会让事情变得简单。如果你经常需要处理每一个节点,平坦的结构就能让你很方便地用 for node in tree
来操作。当然,如果你自己定义一个类,可以很容易地让这两种方式都变得简单;不过在和外部系统打交道时,比如转换成JSON格式,可能会比较麻烦。