IPython 将变量加载到工作区:你能想到比这更好的解决方案吗?

Posted

技术标签:

【中文标题】IPython 将变量加载到工作区:你能想到比这更好的解决方案吗?【英文标题】:IPython loading variables to workspace: can you think of a better solution than this? 【发布时间】:2015-01-31 19:37:33 【问题描述】:

我正在从 MATLAB 迁移到 ipython,在进行飞跃之前,我将完成我的最小工作流程,以确保我每天在 MATLAB 上执行的每项数据处理操作都可以在 ipython 上使用。

我目前被困在通过单行命令保存和加载 numpy 数组的非常基本的任务上,例如 MATLAB 的:

>>> save('myresults.mat','a','b','c')
>>> load('myresults.mat')

特别是,我喜欢 MATLAB 的 load 命令的地方在于,它不仅读取 数据文件,但它将变量加载到工作区中,开始使用它们不需要其他任何东西。请注意,例如 numpy.load() 就不是这种情况,它需要另一行才能将加载的值分配给工作区变量。 [见:IPython: how to automagically load npz file and assign values to variables?]

基于该问题的答案和 cmets,我想出了这个肮脏-糟糕-工程-丑陋-编码-但有效的解决方案。我知道它不漂亮,我想知道你是否能想出这个 [1] 的正确版本。

我把它放到 iocustom.py 中:

def load(filename):
    ip = get_ipython()
    ip.ex("import numpy as np")
    ip.ex("locals().update(np.load('" + filename + "'))") 

以便我可以从 ipython 会话运行:

import iocustom
load('myresults.npz')

变量被转储到工作区。

我很难相信没有任何内置功能与此等效,而且更难认为 3 行函数是最佳解决方案。如果您能提出更正确的方法,我将不胜感激。

请记住:

我正在寻找一种也适用于脚本和函数的解决方案。 我知道有“pickle”,但我拒绝使用超过一行的代码来完成简单的“保存”和/或“加载”命令这样的普通操作。 我知道 scipy 提供了“savemat”和“loadmat”,但我想完全迁移,即不使用 mat 文件而是使用 numpy 数组。

提前感谢您的所有帮助。

[1] 顺便说一句:使用 ipython 的人如何轻松保存和加载一组 numpy 数组?经过数小时的谷歌搜索,我似乎无法为这项日常任务找到简单直接的解决方案。

【问题讨论】:

让 (1) 在函数中工作,(2) 修改局部变量,以及 (3) 在 Python3 is a dealbreaker 中工作。没有“正确”的方法可以做到这一点,因为 Python 不鼓励程序员创建动态命名的变量。确实,您将如何开始使用直到运行时才知道名称的变量?您对便利函数的想法很适合交互式使用,但在脚本中使用这样的东西是一种糟糕的编程习惯。 感谢您的回答。如果是这样的话,我会坚持使用 MATLAB,它似乎很容易做到这一点。再次感谢。 MATLAB 最初是作为 FORTRAN 矩阵代码的用户友好前端。工作空间的想法从一开始就是核心(就像之前的 APL 一样)。 Python 最初是一种通用脚本语言。 numpy 添加了数组处理。而 Ipython 是一个基于 Python 构建的强大的交互环境。但是命名空间的 Python 概念仍然存在。 sage 有保存和加载会话的概念:sagemath.org/doc/reference/misc/sage/misc/session.html 【参考方案1】:

如果我把它保存为load_on_run.py:

import argparse
import numpy as np
if __name__=='__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-l','--list', help='list variables', action='store_true')
    parser.add_argument('filename')
    __args = parser.parse_args()
    data = np.load(__args.filename)
    locals().update(data)
    del parser, data, argparse, np
    if __args.list:
        print([k for k in locals() if not k.startswith('__')])
    del __args

然后在ipython 中我可以使用%run 调用它:

In [384]: %run load_on_run testarrays.npz -l
['array2', 'array3', 'array4', 'array1']
In [385]: array3
Out[385]: array([-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1])

它将文件中的数组整齐地加载到ipython 工作区中。

我正在利用魔术%run 运行脚本的事实,将由它定义的所有函数和变量留在主命名空间中。我还没有研究它是如何做到的。

脚本只接受几个参数,加载文件(目前只有.npz),并使用locals().update 技巧将其变量放入本地命名空间。然后我清除了不必要的变量和模块,只留下新加载的。

我或许可以为%run load_on_run 定义一个别名。

我还可以想象这样一个脚本,它允许您通过导入加载变量:from <script> import *

【讨论】:

【参考方案2】:

您可以将 npz 文件中的值分配给全局变量:

import numpy as np

def spill(filename):
    f = np.load(filename)
    for key, val in f.iteritems():
        globals()[key] = val
    f.close()

此解决方案适用于 Python2 和 Python3,以及任何类型的交互式 shell, 不仅仅是 IPython。使用 spill 可用于交互使用,但不适用于脚本 因为

    它使文件能够将任意名称重新绑定到 任意值。这可能会导致令人惊讶的、难以调试的行为,甚至是安全风险。 动态创建的变量名称难以编程。作为 Python 之禅 (import this) 说:“命名空间是一种 好主意——让我们做更多这样的事情!”对于脚本来说,最好是 保留NpzFilef 中的值,并通过索引访问它们, 比如f['x']

【讨论】:

以上是关于IPython 将变量加载到工作区:你能想到比这更好的解决方案吗?的主要内容,如果未能解决你的问题,请参考以下文章

这个暑假还有什么比这更嗨的事情了

比这更简单的方法来展平或合并 php 数组?

整理了大数据学习全套资源,大概没有比这更全的了!

SpringBoot 一个依赖搞定 session 共享,没有比这更简单的方案了!

vue电商后台管理系统保姆级教程(导航目录)——找到比这更详细的算我输

来一波SpringBoot开源项目,没有比这更简单了