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
) 说:“命名空间是一种
好主意——让我们做更多这样的事情!”对于脚本来说,最好是
保留NpzFile
、f
中的值,并通过索引访问它们,
比如f['x']
。
【讨论】:
以上是关于IPython 将变量加载到工作区:你能想到比这更好的解决方案吗?的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot 一个依赖搞定 session 共享,没有比这更简单的方案了!