【问题标题】:Why does `eval` not work within a Python class function?为什么 `eval` 在 Python 类函数中不起作用?
【发布时间】:2020-04-29 08:28:03
【问题描述】:

假设我有一个带有 Pandas 数据框 df 作为属性的 python 类。我想通过释放一个或多个预定义查询来查询df,使用一个或多个查询句柄作为参数提供的类函数:

import pandas as pd
import numpy as np

class doorn:
    def __init__(self):
        self.name = 'foo'
        self.df = pd.DataFrame(data={'A':np.arange(0, 10), 'B':np.arange(5, 15), 'C':np.arange(14, 24)}, index=[x for x in range(0, 10)])

    def query_df(self, *query):
        # query arguments must by formatted as 'q1', 'q2' etc
        queries = [q for q in query]

        q1 = self.df.loc[self.df.A > 2].index
        q2 = self.df.loc[self.df.B < 13].index
        q3 = self.df.loc[self.df.C > 15].index

        sel_rows = set().union(*[eval(x, globals(), locals()) for x in queries])

        self.df = self.df.loc[sel_rows]

现在,eval 似乎找不到它提供的查询字符串的实例:

>>> foo = doorn()
>>> foo.query_df('q1', 'q2')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 17, in query_df
  File "<input>", line 17, in <listcomp>
  File "<string>", line 1, in <module>
NameError: name 'q1' is not defined

我的猜测是q1q2q3 不存在于行理解命名空间中。或者别的什么,因为我还没有真正了解命名空间。我已经尝试通过提供globals()locals() 作为eval 的附加参数来解决这个问题,正如docs 中所建议的那样,但没有成功。

我该如何解决这个问题?我什至可以完全不使用eval 吗?

【问题讨论】:

  • 使用eval(queries[0]) 有效。此外,用 for 循环替换 for 理解并附加到列表也可以。这可能是相关的:stackoverflow.com/questions/50624105/…
  • 是的,它适用于 for 循环,感谢您的建议。
  • 没问题。我不完全确定它为什么会起作用,所以如果有人添加一个好的答案会很好:)

标签: python pandas namespaces eval nameerror


【解决方案1】:

我认为这是因为您的理解循环中的locals() 与您的函数中的不同,因此它们不包含“q1”。您可以使用全局变量,但我不建议这样做。 此外,使用 eval 可能来自用户输入的内容可能是危险的,因为它可以执行恶意代码。

我建议您将预定义查询列表存储在字典中,如下例所示:

class doorn:
    def __init__(self):
        self.name = 'foo'
        self.df = pd.DataFrame(data={'A':np.arange(0, 10), 'B':np.arange(5, 15), 'C':np.arange(14, 24)}, index=[x for x in range(0, 10)])

    def query_df(self, *query):
        # query arguments must by formatted as 'q1', 'q2' etc
        queries = [q for q in query]

        possible_queries = {'q1' : self.df.loc[self.df.A > 2].index,
        'q2' : self.df.loc[self.df.B < 13].index,
        'q3' : self.df.loc[self.df.C > 15].index}

        sel_rows = set().union(*[possible_queries[x] for x in queries])

        self.df = self.df.loc[sel_rows]

希望这会对你有所帮助。

【讨论】:

  • 使用字典是一个明确的改进,同时避免了eval 问题。
猜你喜欢
  • 1970-01-01
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-03
相关资源
最近更新 更多