2017-10-10 85 views
3

我一直在问到功能添加到以下功能:如何分割与标志控制的多个行为的功能

def maybe_do_thing(x, y, z, really_do_thing): 
    if really_do_thing: 
    return f(x, y, z) # returns a list 
    return []   # an empty list if we did nothing 

具体来说,它应该也能够调用​​,通过附加的控制旗。显而易见的实现是:

def maybe_do_things(x, y, z, do_f, do_g): 
    results = [] 
    if do_f: 
    results.extend(f(x, y, z)) 
    if do_g: 
    results.extend(g(x, y)) # g needs slightly different params 
    return results 

为了清楚起见,的f和g的任意子集可以被称为:两者,既不,或者只是一个,根据两个单独的标志。 f和g在概念上是相关的,所以按照这种方式将它们组合在一起是很有意义的,但对我来说感觉相当不满意:真正的maybe_do_things只是多个通过多个标志伪装成一个函数的函数。

我很确定这是一个反模式,但我不知道它叫什么或正确的模式来解决它。我觉得我应该能够以一种方便的方式将它分成多个自给自足的函数,就像调用复合函数一样方便,或者以某种方式清理复合函数的API,使它不仅仅是一个大块。

就在每个调用点内联maybe_do_things不是很好:这可能是很好的,如果主叫方提前知道其中的F和G将被执行的时间,但是这两个都是在运行时确定。因此,每个调用者都需要完整的当前函数体,以及表示现在重复的x/y/z变量的局部定义。

我不认为将来会有更多的功能被添加到这个功能中,所以至少我不必担心参数列表爆炸。也许我的“明显”实现实际上是最好的折衷?

+0

如果调用者有足够的信息来知道是否传递'do_f'或'do_g',他们有足够的信息来只是自己打电话给对方。在不知道更多关于这些标志以及函数被调用的地方/方式的情况下分析这个有点困难。但是有一种可能性不是将'really_do_thing'想象为是否调用'f',将该参数称为'context'等的“标志”。然后每个呼叫站点传递一个包含所有必要信息的“上下文”来决定实际执行的操作。更好的做法可能是将背景变成一个具有f,g等等作为方法的对象。 – BrenBarn

+0

是的,他们有足够的信息可以自己调用正确的功能。但是,将'maybe_do_things'函数传递给'maybe_do_things'函数要比将整个'if_i_do_f()函数传递给if_do_things(...,should_i_do_f())要容易得多,如果should_i_do_f():f(x,y,z )',如果'f'是一件复杂的事情。 – amalloy

回答

-1

你可以计算每个函数有多少个arg。

def maybe_do_thing(funcs, *args): 
    res = [] 
    for func in funcs: 
    num_arg = func.func_code.co_argcount 
    new_arg = args[:num_arg] 
    res.append(func(*new_arg)) 
    return res 

def print_f(string): 
    return string + 'a' 

def print_f2(string, string2): 
    return string + 'a' + string2 

print maybe_do_thing([print_f, print_f2], 'd', 'c') 

['da', 'dac'] 
1

我不明白什么是功能maybe_do_things而不是调用f(x,y,z)g(x,y,z)如果主叫方已经知道其中一方面前致电的原因,而是一个解决方案可能是实现决策代码内部maybe_do_things与4个可能的结果的函数:既不,既,F或G,像这样:

def maybe_do_things(x,y,z, problem): 
    results = [] 
    decision = decide(problem) 
    if decision == 'both': 
     return results.extend(f(x,y,z)+g(x,y)) 
    elif decision == 'neither': 
     return results 
    elif decision == 'f': 
     return results.extend(f(x,y,z)) 
    elif decidion == 'g': 
     return results.extend(g(x,y))