Pull to refresh

Comments 9

Вместо лямбд для операторов проще и удобнее использовать функции из модуля operator:

К тому же они работают чуть быстрее, так как убирают лишний вызов функции.
Согласен! Ещё у меня была мысль вытащить операторы из класса floatfloat.__add__ и т.п., но некрасиво вытаскивать приватные методы из классов.

С операторами из модуля operator код меняется на:
import operator
OPERATORS = {'+': (1, operator.add), '-': (1, operator.sub),
             '*': (2, operator.mul), '/': (2, operator.truediv)}

Но в моих замерах я не заметил разницы в производительности.
С операторами из operator:
%timeit eval2("15/(7-(1+1))*3-(2+(1+1))*15/(7-(1+1))*3-(2+(1+1))*(15/(7-(1+1))*3-(2+(1+1))+15/(7-(1+1))*3-(2+(1+1)))")
10000 loops, best of 3: 141 µs per loop

С lambda функциями:
%timeit eval_("15/(7-(1+1))*3-(2+(1+1))*15/(7-(1+1))*3-(2+(1+1))*(15/(7-(1+1))*3-(2+(1+1))+15/(7-(1+1))*3-(2+(1+1)))")
10000 loops, best of 3: 143 µs per loop

Две миллисекунды не считается, это я мышкой шевелил!
У меня на машине более ощутимая разница:

# lambda
%timeit eval_("15/(7-(1+1))*3-(2+(1+1))*15/(7-(1+1))*3-(2+(1+1))*(15/(7-(1+1))*3-(2+(1+1))+15/(7-(1+1))*3-(2+(1+1)))")
1000 loops, best of 3: 310 µs per loop

# builtin
%timeit eval("15/(7-(1+1))*3-(2+(1+1))*15/(7-(1+1))*3-(2+(1+1))*(15/(7-(1+1))*3-(2+(1+1))+15/(7-(1+1))*3-(2+(1+1)))")
10000 loops, best of 3: 72.4 µs per loop

# operator
In [10]: %timeit eval_("15/(7-(1+1))*3-(2+(1+1))*15/(7-(1+1))*3-(2+(1+1))*(15/(7-(1+1))*3-(2+(1+1))+15/(7-(1+1))*3-(2+(1+1)))")
10000 loops, best of 3: 144 µs per loop
Скорость ваших operator сравнима с моей, а лямбда — в 2 раза медленнее. Чем это может быть обусловлено? Это может быть интересно.
Моя система: Python 3.4.1 |Anaconda 2.1.0 (64-bit)| (default, Sep 24 2014, 18:32:42) [MSC v.1600 64 bit (AMD64)] on win32
Скорее всего это не самое узкое место, да и ускоряют они совсем на чуть-чуть.

Еще можно вместо словаря использовать именованный кортеж, он, вроде, тоже чуть-чуть быстрее.

Из экстремальных оптимизаций — можно вынести все обращения к атрибутам из цикла, например:
stack_pop = stack.pop

но это уже не питоник решение
Только mus скорее всего микросекунды
Потерял приведение типа во float. Разницы во времени почти нет gist.github.com/JIghtuse/f4a79de4d1dd4539c960. Вообще, `eval` гораздо больше делает, чем числа считает. Его можно обогнать, но, вероятно, придётся дёргать Си. Скорее всего, он на нём реализован.
Стаадии сортировочной станции и вычисления можно объединить используя двустековый алгоритм Дейкстры (Dijkstra's two-stack algorithm).
Sign up to leave a comment.

Articles