从Python中的函数返回中间结果

sas*_*llo 7 python function

想象一下,我有一个带有一些功能的Python模块:

def sumvars(x, y, z):
    s = x
    s += y
    s += z
    return s
Run Code Online (Sandbox Code Playgroud)

但有时候我想得到一些中间计算的结果(例如,我可以有一个反转矩阵的函数,并且想知道已经计算为中间步骤的行列式).显然,如果它们已经在该函数中完成,我不想再次重做那些计算.

我的第一个想法是返回一个字典:

def sumvars(x, y, z):
    d = {}
    s = x
    d['first_step'] = s
    s += y
    d['second_step'] = s
    s += z
    d['final'] = s
    return d
Run Code Online (Sandbox Code Playgroud)

但我不记得numpy或scipy中返回dicts的任何函数,所以看起来这可能不是一个好主意.(为什么?)通常情况下,我总是要输入sumvars(x,y,z)['final']默认的返回值...

我看到的另一个选项是创建全局变量,但在我的模块中有一堆它们似乎是错误的,我需要记住它们的名字,另外没有附加到函数本身看起来像一个糟糕的设计选择.

对于这种情况,适当的功能设计是什么?

pas*_*sti 5

将常用计算放入其自己的函数中,如Jayanth Koushik建议的那样,如果该计算可以恰当地命名.如果你想从一个单一的函数返回多个值(中间结果和最终结果),那么字典可能取决于什么是你的目标,但在Python它更自然只返回一个元组,如果你的函数是矫枉过正要返回的许多值:

def myfunc():
    intermediate = 5
    result = 6
    return intermediate, result

# using the function:
intermediate, result = myfunc()
Run Code Online (Sandbox Code Playgroud)


zha*_*hen 5

不确定函数属性是否是一个好主意:

In [569]: def sumvars(x, y, z):
     ...:     s = x
     ...:     sumvars.first_step = s
     ...:     s += y
     ...:     sumvars.second_step = s
     ...:     s += z
     ...:     return s


In [570]: res=sumvars(1,2,3)
     ...: print res, sumvars.first_step, sumvars.second_step
     ...: 
6 1 3
Run Code Online (Sandbox Code Playgroud)

注意:正如@BrenBarn所提到的,这个想法就像全局变量一样,当您要重用它们时,先前存储的“中间结果”将无法存储。

  • 我说这是一个坏主意,原因与全局变量差不多。每次对该函数的调用都会占用先前存储的值,因此,如果您从调用堆栈中的多个位置调用它,则可能会很快造成混乱。 (2认同)
  • 我不认为使用方法属性是一种好习惯,因为它们几乎就像使用全局变量一样。在此示例中,每次有人调用sumvars方法时,sumvars.first_step都会更改。 (2认同)

roi*_*ppi 5

通常,当您有两种不同的方式返回数据时,请继续执行两种不同的功能.毕竟,"扁平比嵌套更好".只要一个人打电话给另一个,这样你就不要重复自己了.

例如,在标准库中,urllib.parsehas parse_qs(返回a dict)和parse_qsl(返回a list). parse_qs然后调用另一个:

def parse_qs(...):

    parsed_result = {}
    pairs = parse_qsl(qs, keep_blank_values, strict_parsing,
                      encoding=encoding, errors=errors)
    for name, value in pairs:
        if name in parsed_result:
            parsed_result[name].append(value)
        else:
            parsed_result[name] = [value]
    return parsed_result
Run Code Online (Sandbox Code Playgroud)

非常直截了当.所以在你的例子中似乎很好

def sumvars(x, y, z):
    return sumvars_with_intermediates(x, y, z).final

def sumvars_with_intermediates(x, y, z):
    ...
    return my_namedtuple(final, first_step, second_step)
Run Code Online (Sandbox Code Playgroud)

(我赞成从我的API 返回namedtuples而不是dicts,它更漂亮)

另一个明显的例子是re:re.findall它是自己的函数,而不是一些配置标志search.

现在,标准库是许多作者制作的庞大的东西,所以你会发现每个例子的反例.你会经常看到上面的模式,而不是一个接受一些配置标志的综合函数,我觉得它更具可读性.