一提到写算法就想着用一个很长的函数来实现,这种代码维护起来很麻烦。其实用一个类来做会更好。
如何知道自己写的算法需要使用对象来包装
代码坏味道1,太长并且有多层嵌套
太长是多长呢,Martin Fowler说大概10行的样子。当然这不是硬性的规则,大致的原则就是不要让别人在看一个函数时需要滚动屏幕。
代码坏味道2,横幅式的注释
"""
The following section of code is so distinct that I wrote this comment
"""
简单说在一个很长的函数里面,通过注释来分割几个功能块
代码坏味道3,helper函数嵌套在里面,但是依旧很长
def foo_bar():
def foo_bar_closure(argument):
# ...
# end foo_bar_closure closure
do_the_thing(foo_bar_closure)
# end foo_bar method
代码坏味道4,有很多不需要暴露的helper函数
相信你知道我在说什么
代码坏味道5,在helper函数之间传递状态
相信你知道我在说什么
使用类来包装算法的实例
加入我们要中序遍历二叉树并且将节点放入一个列表并且返回,你可能会这样写。
def inorder_traversal(root):
values = []
if not root: # base case
return values
values.extend(inorder_traversal(root.left))
values.append(root.value)
values.extend(inorder_traversal(root.right))
return values
这样写的缺点就是,如果树很大,会创建大量的列表,性能会受到很大的影响。那下面怎么样:
# 这个函数仅仅被下面的函数使用,不要直接调用!
def inorder_traversal_helper(root, values):
if not root: # base case
return
inorder_traversal_helper(root.left, values)
values.append(root.value)
inorder_traversal_helper(root.right, values)
def inorder_traversal(root):
values = []
inorder_traversal_helper(root, values)
return values
如前所述,这样写会引发坏味道4、5条。最后看一看使用类包装的结果:
class InorderTraversalAlgorithm(object):
def __init__(self):
self.values = []
def run(self, root):
self._run_helper(root)
return self.values
# 下划线开头的是私有方法
def _run_helper(self, root):
if not root: # base case
return
self._run_helper(root.left) # recursive case 1
self.values.append(root.value)
self._run_helper(root.right)