скорость и производительность python eval - PullRequest
0 голосов
/ 10 июня 2019

у меня есть словарь скажем

prices={
    "set1": {
        "price1": 200,
        "price2": 300
         ....
    },
    "set2": {
        "price1": 200,
        "price2": 300,
        ....

    }
}

У меня есть набор правил. скажем

rules={
    "set1": {
        "a>0 and b<10 and price1>300": 1.5,
        "a+b=10 or c>20": 2.5
         ....
    },
    "set2": {
        "a=c and b!=d or price2<100": 3.5,
        "a=b and price2 in range(100,300)": 4,
        ....

    }
}

Здесь a, b, c, d .. - переменные, определенные с некоторыми значениями если какое-либо из правил в соответствующем наборе удовлетворяет, то оно будет добавлено к ценам в prices.

Прямо сейчас я использую if eval(rule) для петель но в общей сложности около 20000 циклов, поэтому выполнение не менее 5 минут.

Есть ли возможность сделать это быстрее?

Я использую Django Framework для этого API

Edit: когда я использую лямбду это показывает ошибку, поскольку переменная не определена

1 Ответ

0 голосов
/ 10 июня 2019

Вы должны использовать лямбды или функции для этого типа процесса.Для этого вам необходимо убедиться, что переменные, используемые в лямбда-выражениях или функциях, находятся в области объявления вашего словаря правил.Но, возможно, это может оказаться трудным, если ваш код и объявления правил не содержатся в одной функции.

Вы не опубликовали достаточно контекстной информации / кода, чтобы мы могли определить, где ваш подход терпит неудачу, но, возможно, пример выведет вас на правильный путь:

prices={
    "set1": {
        "price1": 200,
        "price2": 300
    },
    "set2": {
        "price1": 200,
        "price2": 250
    }
}

def Rule(expression,priceValue):
    return (compile(expression,"<string>","eval"),priceValue)

rules={
    "set1": [
        Rule("a>0 and b<10 and price1>300",1.5),
        Rule("a+b==10 or c>20",2.5)
    ],
    "set2": [
        Rule("a==c and b!=d or price2<100",3.5),
        Rule("a==b and price2 in range(100,300)",4)
    ]
}

context = { "a":5, "b":5, "c":5, "d":0 }
for setId,priceSet in prices.items():
    price = []
    for rule,value in rules[setId]:
        context.update(priceSet)
        if eval(rule,globals(),context):
            price.append(value)
    print(setId,price,sum(price))

# set1 [2.5] 2.5
# set2 [3.5, 4] 7.5 
  • ДляДля ускорения повторных вызовов функции eval () вы можете использовать compile (), чтобы получить «скомпилированную» версию вашей строковой формулы.Это то, что вы должны хранить в своем словаре правил.
  • Содержимое набора правил должно быть только массивом кортежей.Это немного упростит использование списка правил.
  • В ваших примерах выражений правил вы используете один знак равенства (=) для проверки равенства, Python нужен двойной знак равенства, иначе формулы не будут создаватьожидаемые результаты.

Я не уверен, что вы имели в виду под "это добавит к ценам в ценах" .Поскольку ваши правила уже используют price1 и price2 в своих выражениях, им, похоже, требуется содержание словаря цен (или хотя бы одного из его наборов), чтобы получить ответ.Почему (и как) тогда они будут обновлять ту самую структуру данных, на которую они полагаются в ответе?а с какими ключами?Я не мог привести пример, который соответствует этому требованию.Надеюсь, вы сможете адаптировать мой пример к вашим потребностям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...