【问题标题】:Error in list comprehension with `locals()` in pythonpython中使用`locals()`的列表理解错误
【发布时间】:2019-02-21 15:13:30
【问题描述】:

我运行了一个创建多个变量的 python 脚本。现在我想迭代一些与特定模式匹配的数据帧(由脚本创建)并对它们执行简单的操作。最初我想获取list_dfs中每个数据帧的行数(带有shape()),如下图:

['FAILEDRuns_0112',
 'FAILEDRuns_0121',
 'FAILEDRuns_0126',
 'FAILEDRuns_0129',
 'FAILEDRuns_0131',
 'FAILEDRuns_0134',
 'FAILEDRuns_0135',
 'FAILEDRuns_0137',
 'FAILEDRuns_0142',
 'FAILEDRuns_0153',
 'FAILEDRuns_0165',
 'FAILEDRuns_0171',
 'FAILEDRuns_0175']

事实上,如果我这样做:

for i in list(filter(failed_runs_finder.findall, dir())):
    print(locals()[i].shape[0])

我得到了打印到屏幕上的行数:

1
0
0
0
1
0
0
0
0
0
0
0
0

其中包含我需要的信息,但不是我想要的格式。最终我需要知道的是 1 的数量和零的数量,所以我想得到一个列表理解,最终将总和(即 1 的数量)与列表的长度(即总数)进行比较元素。

但是,如果我这样做:

[locals()[i].shape[0] for i in list_dfs]

我收到以下错误:

KeyError: 'FAILEDRuns_0112'

我不太明白错误来自哪里。据我所知,它不是列表推导的语法。

这与在列表理解中使用 locals() 有什么关系吗?

我的第二个选择是迭代地构建一个 df 并得到总和,尽管我认为列表理解更简单,而且我不太明白错误来自哪里。

【问题讨论】:

  • sum 表示1 的数目,用len-sum 表示0 的数目不是更方便吗?
  • 在for循环中你做了print(locals()[i].shape),为什么在列表理解中变成了shape[0]
  • @Rocky Li:确实,代码与输出不匹配,但对我来说,很奇怪我可以在for 循环中做,但不能用列表理解。
  • 为什么你有这么多类似命名的局部变量而不是一个dict

标签: python for-loop list-comprehension


【解决方案1】:

如果您真的必须依赖locals(),请尝试这个:

[v.shape[0] for k, v in locals().items() if k in list_dfs]

但是,正如建议的那样,使用单个 dict 来存储所有名称和 DataFrame 对象可能是一种更好的方法。

如果要获取行数:

from collections import Counter

cnt = Counter(v.shape[0] for k, v in locals().items() if k in list_dfs)

cnt[1]
# 2

cnt[0]    
# 11

【讨论】:

  • 使用dict 代替locals()globals() 似乎是常识。我的脚本正在进入多个目录并将来自不同文件的信息解析为数据帧。那时,当我开始编写脚本时,我发现使用 globals() 与 f-strings 结合是获得多个(相似)数据帧的解决方案,这些数据帧具有通用名称(FAILEDRuns_)但具有唯一标识符(0112、0121 等)。这还有一个好处是我总是可以在spyder 上直观地检查 dfs。肯定会看看如何迭代地构建dict
  • 构建dictDataFrames 肯定会更容易参考。如果您需要依靠globals()locals() 来动态引用一个变量,那么您很快就会遇到这样的范围问题,而dict 您始终拥有跨不同范围的直接引用点。跨度>
猜你喜欢
  • 1970-01-01
  • 2014-04-24
  • 2011-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多