我已经编写了几个按顺序运行的函数,每个函数都将前一个函数的输出作为输入,所以为了运行它,我必须运行这行代码
make_list(cleanup(get_text(get_page(URL))))
而我发现丑陋且效率低下,是否有更好的方法进行顺序函数调用?
答案 0 :(得分:5)
实际上,这与您想要重构常用的复杂表达式或语句的任何情况相同:只需将表达式或语句转换为函数即可。你的表达式恰好是函数调用的组合这一事实没有任何区别(但见下文)。
所以,显而易见的事情就是编写一个包装函数,将函数组合在一起,所以在其他任何地方你都可以对包装器进行简单的调用:
def get_page_list(url):
return make_list(cleanup(get_text(get_page(url))))
things = get_page_list(url)
stuff = get_page_list(another_url)
spam = get_page_list(eggs)
如果你不总是调用完全相同的函数链,你总是可以将你经常调用的部分分解出来。例如:
def get_clean_text(page):
return cleanup(get_text(page))
def get_clean_page(url):
return get_clean_text(get_page(url))
这种重构也为使代码更加冗长但调试更容易打开了大门,因为它只出现一次而不是多次:
def get_page_list(url):
page = get_page(url)
text = get_text(page)
cleantext = cleanup(text)
return make_list(cleantext)
如果你发现自己需要经常对组合函数进行这种重构,你总是可以编写一个生成重构函数的帮助器。例如:
def compose1(*funcs):
@wraps(funcs[0])
def composed(arg):
for func in reversed(funcs):
arg = func(arg)
return arg
return composed
get_page_list = compose1(make_list, cleanup, get_text, get_page)
如果你想要一个更复杂的compose
函数(例如,允许传递多个args /返回值),设计可能会有点复杂,所以你可能想要查看PyPI和ActiveState对于各种现有的实现。
答案 1 :(得分:2)
你可以尝试这样的事情。我总是喜欢分离火车残骸(书中的“清洁代码”称那些嵌套的功能列车残骸)。这更容易阅读和调试。请记住,阅读代码的时间可能比编写代码长两倍,因此更容易阅读。你以后会感谢自己。
url = get_page(URL)
url_text = get_text(url)
make_list(cleanup(url_text))
# you can also encapsulate that into its own function
def build_page_list_from_url(url):
url = get_page(URL)
url_text = get_text(url)
return make_list(cleanup(url_text))
答案 2 :(得分:0)
选项:
cleanup
和make_list
作为装饰器,然后用它们装饰get_text
。答案 3 :(得分:0)
您可以使用以下内容缩短类似的结构:
class ChainCalls(object):
def __init__(self, *funcs):
self.funcs = funcs
def __call__(self, *args, **kwargs):
result = self.funcs[-1](*args, **kwargs)
for func in self.funcs[-2::-1]:
result = func(result)
return result
def make_list(arg): return 'make_list(%s)' % arg
def cleanup(arg): return 'cleanup(%s)' % arg
def get_text(arg): return 'get_text(%s)' % arg
def get_page(arg): return 'get_page(%r)' % arg
mychain = ChainCalls(make_list, cleanup, get_text, get_page)
print( mychain('http://is.gd') )
输出:
make_list(cleanup(get_text(get_page('http://is.gd'))))