Почему `eval` не работает в функции класса Python? - PullRequest
1 голос
/ 29 апреля 2020

Скажем, у меня есть python класс с Pandas фреймом данных df в качестве атрибута. Я хочу запросить 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

Я предполагаю, что q1, q2, q3 отсутствуют в пространстве имен для понимания строк. Или что-то еще, потому что я еще не обнял Пространства имен. Я попытался решить эту проблему, предоставив globals() и locals() в качестве дополнительных аргументов для eval, как предложено в документах , но безуспешно.

Как я могу решить это? Могу ли я вообще отказаться от использования eval?

1 Ответ

2 голосов
/ 29 апреля 2020

Я думаю, это потому, что locals() в вашем понимании l oop не совпадают с теми, что в вашей функции, поэтому они не содержат '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]

Надеюсь, это поможет вам.

...