【问题标题】:numpy, scipy, pass large number of variables between functions, modules, easily [closed]numpy,scipy,在函数、模块之间传递大量变量,很容易[关闭]
【发布时间】:2015-04-22 12:22:46
【问题描述】:

所以我使用 numpy、scipy、matplotlib 进行科学计算,运行一些模拟并尝试对它们进行模块化操作,但我遇到了问题。尝试从 matlab 调整我的工作流程。

在 matlab 中,我通常会编写几个分布在单独文件中的函数——一个以参数作为参数运行模拟,一个通过输入不同的参数值对这些模拟的结果进行评估,一个单独的函数绘制根据参数的结果和标题等。通常参数集和结果集将是不同类型变量的非常大的组合,所以我会将它们打包成结构。 matlab 中有一个名为 v2struct 的函数,可以轻松地在我将运行的不同操作之间打包和解包这些变量组合。另外,我似乎没有遇到 matlab 中的命名空间问题。

现在在 python 中,我希望能够做同样的事情。我正在慢慢学习如何编写类,但我找不到关于如何在我的文件系统中组织这些的很好的文档。因为我更喜欢编写函数和脚本(我认为这是正确的术语)并使用 ipython %run script.py` 运行它们,所以我想利用相同的能力在之间传递大量参数和结果变量运行模拟、测试结果和绘制结果的各种功能。这就是为什么我一直在尝试将内容打包到字典中,然后将它们解包到其他名称空间中。这将使我可以 100% 更轻松地将我为将这些模拟试验为模块化片段而完成的代码脚本分解。

但每次我试图弄清楚如何去做时,我都会看到很多“没有人应该动态创建变量”和“我无法想象为什么你会想要解压缩字典”。那么在函数周围传递字典有什么意义呢?我期待有很多不同的函数可以使用相同的变量集。是的,我知道这意味着课程。但它们真的很难设计,至少对于科学计算来说是这样。或者也许只是为了我。有没有中间立场?

有没有人有任何教程的链接可以教你如何解决这个问题?教您如何设计代码的资源(也就是我从 900 亿个“python 入门”教程中了解如何使用 python 编写脚本,但是在弄清楚如何将我的脚本转换为模块(即重构)方面存在差距)。我知道如何编写一个类,但不知道如何选择如何将我的脚本放入类中,或者何时将事物划分为子类,或者特别是如何使用我用我的一个脚本创建的类。


好的,这是我找到的解决方案: 将我的脚本(所有共享一个命名空间)分解为函数(作用于相同的变量,但在不同的命名空间中)我创建了一个密钥列表('tuple','of','keys'),我用它来将函数命名空间中的变量打包到输出字典中:

returnVals = dict();
for k in keylist:
    returnVals[k]=locals()[k]

return returnVals

为了让我自己更容易(我希望),我将参数名称自动打包到密钥列表中,如下所示:

argNames = my_function.func_code.co_varnames[:my_function.func_code.co_argcount]

然后keynames = argNames + ('stuff','function','computes')

唯一有点烦人的是必须重写函数参数中的所有变量名(即def subfunction(sameVarName1,sameVarName2,etc):) 这样当我调用 subfunction(**whateverINamedMyReturnValsInLastFunction) 时,该函数就知道 kwargs 中将包含哪些键。但是,我认为从长远来看,当我(希望)能够重用我的代码时,这将对我有所帮助。

【问题讨论】:

  • 这也可能是类的一个很好的用例。毕竟,Python 中的一个类至少只是一个附加了一些额外结构的字典。不同函数之间共享的数据可以对属性进行分类,以便任何需要它的方法都可以访问它。
  • MATLAB 结构与 Python 字典大致匹配;带有列表的单元格。类是内置在 Python 中的,而不是后期添加的。模块命名空间也是 Python 组织的核心。
  • 您可以尝试使用 .mat 文件从 MATLAB 程序传递数据 - 使用 scipy.io.loadmat 函数。

标签: python matlab numpy matplotlib


【解决方案1】:

我通常同意“任何人都不应该动态创建变量” 但强烈不同意“我 [原文如此] 无法想象你为什么要打开包装 字典。”[1]

Unpacking a dictionary 是解决您当前问题的好方法:

def foo():
    result = dict()
    # fill `result` with values
    result[key] = value
    ...
    return result

def bar(arg1, arg2, ...):
    ...

result = foo()
bar(**result)

最后一行解包result 中的键/值对,并将它们作为参数传递给bar。

bar(**{key1:value1, key2:value2})

等价于

bar(key1=value1, key2=value2)

我不认为you really need to define a class 只是为了传递值。一本字典就可以了。


[1]好吧,再想一想,这取决于“解包字典”的含义。将字典解包到全局命名空间是个坏主意,但将字典解包到函数就可以了。

【讨论】:

  • 亲爱的主,这有很大帮助。我之前遇到过 **kwargs ,但错过了必须在函数参数中解包的变量名的区别。我想否则该函数不知道 kwargs['x'] 将被分配,所以它会产生一个名称错误。现在我正在做一些 hacky 来快速打包它们-return locals()。这使得脚本重构变得更加容易。但我可能应该考虑清理垃圾之类的,是吗?
  • 我不确定您对垃圾清理有什么想法。但要记住的一件事是,如果您return locals(),result = foo() dict 可能有比您需要传递给bar 更多的键/值对。你可以使用def bar(arg1, arg2, **kwargs)来允许你调用bar(**result)而不清理额外的键/值对——**kwargs会很高兴地吞下所有额外的东西。
  • 但是请注意,虽然这可能会帮助您快速重构,但这也是一种草率的编程,可能会导致有些难以发现的静默错误,因为bar(**result) 不会在您通过result 带有拼写错误键的字典。
  • 好的!我通过制作输出键列表并仅使用locals()[key] 项目更新我的返回列表来选择适当的变量。我认为这应该让我摆脱函数定义中的 **kwargs,如果我要大量更改参数,这很好。到目前为止它似乎工作 - 还没有经过实战测试,但我对这种语言感到不那么沮丧(现在,哈哈!)。感谢您的所有帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-21
  • 2020-07-02
  • 2020-05-16
  • 2017-07-01
  • 2013-04-09
  • 2013-03-07
相关资源
最近更新 更多