Multiple Value Return Pattern in Python (not tuple, list, dict, or object solutions)
有几个关于"在python中返回多个值"的讨论,例如1,2。这不是我想在这里找到的"多值返回"模式。无论您使用什么(元组、列表、dict、对象),它仍然是一个返回值,您需要以某种方式解析该返回值(结构)。
多个返回值的真正好处是在升级过程中。例如,
原来,你有
1 2 3 | def func(): return 1 print func() + func() |
然后您决定
1 2 3 4 5 6 | def func(): return 1,"extra info" value, extra = func() print value # 1 (expected) print extra # extra info (expected) print func() + func() # (1, 'extra info', 1, 'extra info') (not expected, we want the previous behaviour, i.e. 2) |
以前的代码(
我不知道我是否把问题讲清楚了…您可以看到clisp示例。在python中是否有一种实现此模式的等效方法?
编辑:我把上面的clisp片段放到网上,供你快速参考。
让我在这里为多返回值模式放置两个用例。可能有人可以对这两种情况有其他解决方案:
- 更好的支持平滑升级。这在上面的示例中显示。
- 具有更简单的客户端代码。请参阅我目前为止的以下替代解决方案。使用异常可以使升级过程顺利进行,但需要花费更多的代码。
当前的替代方案:(它们不是"多值回报"结构,但它们可以是满足上述某些点的工程解决方案)
以下是一些解决方案:
- 根据@yupbank的回答,我把它形式化为一个装饰,见
github.com/hupili/multiret 。 - 上面第八个选项说我们可以结束一个课程。这是我们目前采用的工程解决方案。为了包装更复杂的返回值,我们可以使用元类根据需要生成所需的包装类。还没有尝试过,但这听起来是一个强有力的解决方案。
试试看吗?
我做了一些尝试,但不太优雅,但至少是可行的。作品:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | import inspect from functools import wraps import re def f1(*args): return 2 def f2(*args): return 3, 3 PATTERN = dict() PATTERN[re.compile('(\w+) f()')] = f1 PATTERN[re.compile('(\w+), (\w+) = f()')] = f2 def execute_method_for(call_str): for regex, f in PATTERN.iteritems(): if regex.findall(call_str): return f() def multi(f1, f2): def liu(func): @wraps(func) def _(*args, **kwargs): frame,filename,line_number,function_name,lines,index=\ inspect.getouterframes(inspect.currentframe())[1] call_str = lines[0].strip() return execute_method_for(call_str) return _ return liu @multi(f1, f2) def f(): return 1 if __name__ == '__main__': print f() a, b = f() print a, b |
神奇的是,在处理结果时,您应该使用设计模式blablablabla而不是实际操作,而是使用一个参数作为操作方法,对于您的情况,可以使用以下代码:
1 2 3 4 5 6 7 8 | def x(): #return 1 return 1, 'x'*1 def f(op, f1, f2): print eval(str(f1) + op + str(f2)) f('+', x(), x()) |
如果需要更复杂情况的通用解决方案,可以扩展f函数,并通过op参数指定流程操作。
您的案例需要进行代码编辑。但是,如果您需要一个hack,您可以使用函数属性返回额外的值,而不修改返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def attr_store(varname, value): def decorate(func): setattr(func, varname, value) return func return decorate @attr_store('extra',None) def func(input_str): func.extra = {'hello':input_str +" ,How r you?", 'num':2} return 1 print(func("John")+func("Matt")) print(func.extra) |
演示:http://codepad.org/0hjovfcc
但是,请注意,函数属性的行为将类似于静态变量,您需要小心地为它们分配值,附录和其他修饰符将作用于以前保存的值。