在Python/iPython中,是否有任何方法可以仅从列表中的名称访问或调用对象或变量属性



我有一个Jupyter笔记本。我知道它不适合大型作品,但在许多情况下,它是我必须使用的工具。

经过一些计算,我最终在内存中得到了几只我想腌制的熊猫DataFrame。所以我做

df_name.to_pickle(filename)

然而,我想使用创建一个所有DataFrame的列表

df_list = %who DataFrame

然后我想做一些类似的事情

for varname in df_list:
varname.to_pickle(f'{varname}.pickle')

这当然不起作用,因为varname是一个字符串,而不是具有关联.to_pickle方法的DataFrame对象

所以我愚蠢的问题是,访问实际对象varname的最佳方式是什么,而不仅仅是访问具有其名称的字符串?

注意:如果我创建一个实际DataFrame的列表,这些对象在内存中是相当大的,所以我可能会遇到内存问题。

感谢

@matszwecja在评论中指出,最合理的方法是在制作时收集它们。这对你自己和其他人来说也将是最清楚的。此外,在开发代码时更健壮、更易于调试
然而,您似乎在更抽象地考虑对内核命名空间中的数据帧进行迭代,并且有可能做到这一点,并逐步自动清除数据帧。也许这并不是那么容易。例如,您已经发现无法使用df_list = %who DataFrame简单地创建可用列表。(它显示输出单元格中的名称,但不是Python可以使用的方式。(

如果你真的想这样做,这里有一个选项会起作用。第一部分设置一些伪数据帧,然后列出它们的字典:

import pandas as pd
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
input ='''
River_Level Rainfall
0.876       0.0
0.877       0.8
0.882       0.0
0.816       0.0
0.826       0.0
0.836       0.0
0.817       0.8
0.812       0.0
0.816       0.0
0.826       0.0
0.836       0.0
0.807       0.8
0.802       0.0
''' 
df_name_one = pd.read_table(StringIO(input), header=0, index_col=None,  delim_whitespace=True)
input ='''
River_Level Rainfall
0.976       0.1
0.977       0.5
0.982       0.0
0.916       0.3
0.926       0.0
0.996       9.0
0.917       0.8
0.912       0.0
0.916       0.0
0.926       0.1
0.836       0.0
0.907       0.6
0.902       0.0
''' 
df_name_two = pd.read_table(StringIO(input), header=0, index_col=None,  delim_whitespace=True)
list_of_dfs_dicts = []
for obj_name in dir():
obj_type_str = str((type(eval(obj_name))))
#print(obj_type_str)
if "DataFrame" in obj_type_str: 
#print(obj_name)
#print(obj_type_str)
list_of_dfs_dicts.append({obj_name: eval(obj_name)})

现在,列表中的每个条目都是数据帧对象和数据帧的名称。这可以通过笔记本中的一行进行迭代和腌制:

[df.to_pickle(f'{varname}.pkl') for d in list_of_dfs_dicts for varname,df in d.items()];

这实际上相当于这个,更容易阅读:

for d in list_of_dfs_dicts:
for varname,df in d.items():
df.to_pickle(f'{varname}.pkl')

对于这个独立的答案,我将整个数据帧作为收集的列表和字典的一部分列出。对于这些数据帧,内存不是一个问题,我希望它能以小步骤很好地说明问题。

然而,记忆是你关心的问题。您可以改变收集步骤,不将整个数据帧添加到列表中,如下所示:

import pandas as pd
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
input ='''
River_Level Rainfall
0.876       0.0
0.877       0.8
0.882       0.0
0.816       0.0
0.826       0.0
0.836       0.0
0.817       0.8
0.812       0.0
0.816       0.0
0.826       0.0
0.836       0.0
0.807       0.8
0.802       0.0
''' 
df_name_one = pd.read_table(StringIO(input), header=0, index_col=None,  delim_whitespace=True)
input ='''
River_Level Rainfall
0.976       0.1
0.977       0.5
0.982       0.0
0.916       0.3
0.926       0.0
0.996       9.0
0.917       0.8
0.912       0.0
0.916       0.0
0.926       0.1
0.836       0.0
0.907       0.6
0.902       0.0
''' 
df_name_two = pd.read_table(StringIO(input), header=0, index_col=None,  delim_whitespace=True)
df_list = []
for obj_name in dir():
obj_type_str = str((type(eval(obj_name))))
if "DataFrame" in obj_type_str: 
df_list.append(obj_name)
for df_name in df_list:
eval(df_name).to_pickle(f'{df_name}.pkl')

请记住,尽管eval()需要小心使用。特别是它打开了代码注入的大门
这样做并不是在检查。例如,在开发过程中,您可能会在某个时刻错误地生成大量数据帧(例如(,如果这些数据帧仍在内核的命名空间中,则它们将ALL通过酸洗步骤进行酸洗。这就是为什么收集你想要的东西更实用的原因;从长远来看更安全/稳健。我只是觉得你使用df_list = %who DataFrame的想法很有趣。

最新更新