【问题标题】:Return many variables in Python without dictionary [closed]在没有字典的情况下返回 Python 中的许多变量 [关闭]
【发布时间】:2014-11-13 22:18:54
【问题描述】:

我有一个函数compute_params(),它计算我想在另一个函数中使用的许多变量,比如main_func()。目前,我的代码类似于:

def compute_params(i):
    a = i/2
    b = a + 2.
    c = 2*a/b - 1.
    d = a + b + c
    e = ((a + 1.)**2 - d)/c
    # ...and so on with more complex computations and more variables.

    return a, b, c, d, e

def main_func(imax):
    for i in range(imax):
        a, b, c, d, e = compute_params(i)
        # Do something with a, b, c, ...

我的问题是:

  • 考虑到速度问题,返回并获取 5、10 个变量(或者在我的现实生活中的函数中甚至更多)是否有问题?
  • 如果第一个问题的答案是肯定的,考虑到我需要将实变量名称保留在main_func() 中(将它们放入大方程式中),如何简单地使用字典或类似的东西来做到这一点?

注意:只是为了理解我为什么要这样做,我的函数 compute_params() 在我的代码中的不同位置使用,这就是为什么它的内容不直接包含在 main_func() 中。

编辑 回答我的几个建议:我想避免使用类或字典,因为 (1) 我的变量唯一的共同点是在同一个方程中有用,因此有没有合乎逻辑的理由将它们分组到一个对象中,最重要的是(2),因为这些系数在已经很难阅读的复杂方程中出现了数百次,我想避免像 params.a + params.b/params.c 这样的事情,我现在只是写 @987654328 @。

【问题讨论】:

  • 严格来说,您不会返回多个值,而是返回一个 tuple。
  • 轻松作为元组返回 (a, b, c...)
  • 过多的参数和/或返回值通常被认为是代码异味——您能否将这些参数封装在其他东西中(包括,是的,字典)?
  • @Matthias 我知道这种微妙之处,但除非有办法在 Python 中的函数中真正返回多个值,否则我想不区分返回多个变量和返回一个元组是合理的.
  • @jonrsharpe 我在我的问题中添加了一点来回答这个建议(我在你的回答的第一条评论中表达了同样的想法)。

标签: python dictionary return


【解决方案1】:

这本身不存在速度问题。如果此代码在一个紧密的循环中,系统运行速度太慢,无法满足您的需求,您使用了分析器并发现问题出在此处,那么可能存在问题。这根本不是我寻求速度改进的第一个地方。

也就是说:这是不可读的代码。您需要更好的变量名称,并且传递大量变量而没有更多的结构是错误代码的标志。 “compute_params”本身也毫无意义;什么样的参数?

这些变量难道不是意思吗?不能将它们组合成一个或少数类吗?

我想您会发现,如果您可以将其中的一些组合到一个命名良好的类中,那么您想要进行的一些计算将自然而然地适合该类的方法。但至少,您可以只使用类实例,而不是必须到处重复的笨重的变量列表。

【讨论】:

  • 好吧,实际上问题中的代码只是一个示例。我不确定如果我复制粘贴我正在使用的真实代码,它会对人们有多大帮助。我使用的变量是用于计算不同矩阵中其他系数的系数,这些矩阵定义了 8 阶系统 + 物理系统的边界条件。
【解决方案2】:

如果您不喜欢传递许多变量,可以尝试使用namedtuple。然后你只需要传递这个 namedtuple 并且仍然可以很好地处理变量而无需解包列表:

from collections import namedtuple
variables = namedtuple('variables', ['a', 'b', 'c', 'd', 'e'])
var = variables(1,2,3,4,5)
var.a # 1
var.b # 5

【讨论】:

  • 在这种情况下这是一个很好的建议,我没有考虑过!无论如何,此解决方案与 jonrsharpe 建议的解决方案具有相同的缺点...
  • 谢谢你,你终于让我找到了最适合我的解决方案(请参阅my comment to jonrshape)!
  • 我后退...我的“解​​决方案”至少没用,更可能是愚蠢的(我做了一些计时,它比我的初始代码慢得多!) .现在还在想这些事情……
  • @Falken 我想我无法理解,你的意思是namedtuple-Version(或任何由此演变而来的版本)比将单个变量a 传递给e 更快或更慢?
  • namedtuple 版本非常慢(即使在我的小示例代码中),如果我将所有内容打包在一个 namedtuple 中,然后在我的主函数中用 a, b, c = compute_params(i) 之类的东西解压它以避免var.a,@ 987654329@和直接有a和b。
【解决方案3】:

考虑到您的参数的计算方式,一个选择是一个简单的类:

class Params(object):

    def __init__(self, i):
        self.a = i / 2.0
        self.b = self.a + 2
        self.c = (2 * (self.a / self.b)) - 1.
        self.d = self.a + self.b + self.c
        self.e = (((self.a + 1) ** 2) - self.d) / self.c

然后您可以传递此类的单个实例:

def main_func(imax):
    for i in range(imax):
        params = Params(i)
        # use e.g. params.a in an equation

或者,使用字典可能类似于:

def create_params(i):
    params = {'a': i / 2.0}
    params['b'] = params['a'] + 2
    params['c'] = (2 * (params['a'] / params['b'])) - 1
    params['d'] = params['a'] + params['b'] + params['c']
    params['e'] = (((params['a'] + 1) ** 2) - params['d']) / params['c']
    return params

然后可以通过按键轻松访问:

def main_func(imax):
    for i in range(imax):
        params = create_params(i)
        # use e.g. params['a'] in an equation

或者,如果您有一个带有参数(或某个子集)的函数,您可以将字典直接解压缩到其中:

def func(a, d, **kwargs): # kwargs mops up unused parameters
    # does stuff with a and d
    return result

result = func(**params)

【讨论】:

  • 感谢您的详细回答,但这正是我希望可以避免的。这些变量用于有些庞大的方程式,阅读起来已经很痛苦,我想避免写类似 params.a2/params.b + 1./params.c - params.d 而不是 a2/b + 1./c - d...
  • @Falken 如果您将总和封装在采用所需参数的函数中(请参阅我的答案末尾的func),您可以使用字典解包相对巧妙地处理这个问题。
  • 好的,我明白你的意思了,我没明白这一点。这可能是我问题的最佳答案。我会考虑一下并在我的真实代码中对其进行测试,如果一切正常,我会回来接受您的回答(抱歉,由于我的声誉低,我无法投票:-/)
  • 嗯...我不知道如何使您的解决方案正常工作。您能否修改您的答案以使用 **kwargs 作为函数参数来提供更完整和更有效的示例?更多:你不能使用未定义的变量作为 dict 键,我猜你在写 params[a] 时认为 params['a'] 等。
  • @Falken 你是对的,对不起;我错过了整个第三个代码块和第四个注释中的引号。然而,这并没有改变最后一个 - 一旦你有了字典,你就可以解压它来为函数提供关键字参数。
【解决方案4】:

你(有点)要求宏吗?

你可以试试karnickel。

【讨论】:

  • 有趣,我可能有一天会需要这种东西,不知道!但就目前而言,我终于找到了解决方案,综合了其他几个建议。
【解决方案5】:

这就是人们发明面向对象编程的原因之一,其中相同的变量可以与一堆函数相关。

【讨论】:

  • OOP 的问题是你需要用 class_name.a、class_name.b 等替换短而简单的变量名称,正如我在其他 cmets 中所说的那样,即使你并不真的需要对这些变量进行分组,这些变量只是一堆有用的系数,有时没有明显的关系。
  • 顺便说一句,在OOPS对象中有成员变量和成员函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-27
  • 1970-01-01
  • 1970-01-01
  • 2013-09-25
  • 1970-01-01
  • 1970-01-01
  • 2012-07-21
相关资源
最近更新 更多