Эффективная memoization в Python

у меня есть задача, которую нужно решить, и самая важная часть на данный момент-сделать сценарий максимально эффективным по времени. Одним из элементов, которые я пытаюсь оптимизировать, является memoization в одной из функций.

Итак, мой вопрос: какой из следующих 3-4 методов является наиболее эффективным / быстрым методом реализации memoization в Python?

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

Решение 1 - Использование изменяемой переменной из внешней области

это решение часто показано в качестве примера memoization, но я не уверен, насколько оно эффективно. Я слышал, что использование глобальных переменных (в данном случае это переменная из внешней, а не глобальной области) менее эффективно.

def main():
    memo = {}
    def power_div(n):
        try:
            return memo[n]
        except (KeyError):
            memo[n] = (n ** 2) % 4  # example expression, should not matter
            return memo[n]
    # extensive usage of power_div() here

решение 2-Использование изменяемого по умолчанию аргумента

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

def main():
    def power_div(n, memo={}):
        try:
            return memo[n]
        except (KeyError):
            memo[n] = (n ** 2) % 4  # example expression, should not matter
            return memo[n]
    # extensive usage of power_div() here

или, может быть, следующая версия (будучи на самом деле комбинацией решений 1&2) более эффективно?

def main():
    memo = {}
    def power_div(n, memo=memo):
        try:
            return memo[n]
        except (KeyError):
            memo[n] = (n ** 2) % 4  # example expression, should not matter
            return memo[n]
    # extensive usage of power_div() here

решение 3-атрибут функции

это еще один довольно распространенный пример memoization в Python - объект memoization хранится как атрибут самой функции.

def main():
    def power_div(n):
        memo = power_div.memo
        try:
            return memo[n]
        except (KeyError):
            memo[n] = (n ** 2) % 4  # example expression, should not matter
            return memo[n]
    # extensive usage of power_div() here

резюме

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

Я знаю что есть и другие решения для мемоизации (например,Memoize декоратор), но мне трудно поверить, что это более эффективное решение, чем перечисленные выше. Поправьте меня, если я ошибаюсь.

спасибо заранее.

2 ответов


различные стили доступа к переменным уже были синхронизированы и сравнены по адресу: http://code.activestate.com/recipes/577834-compare-speeds-of-different-kinds-of-access-to-var Вот краткое резюме: локальный доступ бьет нелокальные (вложенные области), которые бьют глобальный доступ (область модуля), который бьет доступ к встроенным.

ваше решение #2 (с локальным доступом) должно выиграть. Решение #3 имеет медленный точечный поиск (который требует поиска по словарю). Решение № 1 использует нелокальный (вложенная область) доступ, который использует ячейки-переменные (быстрее, чем поиск dict, но медленнее, чем локальные).

Также обратите внимание,KeyError класс исключений является глобальным поиском и может быть ускорен путем его локализации. Вы можете полностью заменить try/except и использовать . И даже это может быть ускорено с помощью метода bound. Конечно, ваш самый простой повышение скорости может просто прийти от пробы pypy : -)

короче, там есть много способов настроить этот код. Просто убедись, что оно того стоит.


в интересах людей, которые натыкаются на этот вопрос, ища способ сделать memoization в python, я рекомендую fastcache.

он работает на python 2 и 3, быстрее, чем любой из описанных выше методов, и дает возможность ограничить размер кэша, чтобы он случайно не стал слишком большим:

from fastcache import clru_cache

@clru_cache(maxsize=128, typed=False)
def foo(cat_1, cat_2, cat_3):
    return cat_1 + cat_2 + cat_3

установка fastcache проста, используя pip:

pip install fastcache

или conda:

conda install fastcache