Programming

메모 란 무엇이며 파이썬에서 어떻게 사용할 수 있습니까?

procodes 2020. 3. 1. 16:04
반응형

메모 란 무엇이며 파이썬에서 어떻게 사용할 수 있습니까?


방금 파이썬을 시작했는데 메모무엇인지 , 어떻게 사용 하는지 전혀 몰랐 습니다. 또한 간단한 예가 있습니까?


Memoization은 메소드 입력을 기반으로 메소드 호출의 결과를 기억 ( "memoization"→ "memorandum"→ 기억해야 함) 한 다음 결과를 다시 계산하지 않고 기억 된 결과를 반환하는 것을 효과적으로 말합니다. 메소드 결과의 캐시로 생각할 수 있습니다. 자세한 내용은 알고리즘 소개 (3e), Cormen et al.

파이썬에서 메모를 사용하여 계승을 계산하는 간단한 예는 다음과 같습니다.

factorial_memo = {}
def factorial(k):
    if k < 2: return 1
    if k not in factorial_memo:
        factorial_memo[k] = k * factorial(k-1)
    return factorial_memo[k]

더 복잡해지고 메모 프로세스를 클래스로 캡슐화 할 수 있습니다.

class Memoize:
    def __init__(self, f):
        self.f = f
        self.memo = {}
    def __call__(self, *args):
        if not args in self.memo:
            self.memo[args] = self.f(*args)
        #Warning: You may wish to do a deepcopy here if returning objects
        return self.memo[args]

그때:

def factorial(k):
    if k < 2: return 1
    return k * factorial(k - 1)

factorial = Memoize(factorial)

파이썬 데코레이터 에는 " 데코레이터 " 라는 기능 이 추가되어 동일한 기능을 수행하기 위해 다음을 간단히 작성할 수 있습니다.

@Memoize
def factorial(k):
    if k < 2: return 1
    return k * factorial(k - 1)

파이썬 데코레이터 라이브러리 라는 유사한 장식이 memoized약간 더 견고보다 Memoize여기에 표시된 클래스를.


Python 3.2의 새로운 기능은 functools.lru_cache입니다. 기본적으로, 그것은 단지 128 개 가장 최근에 사용 된 통화를 캐시하지만 당신은을 설정할 수 있습니다 maxsize위해 None캐시가 만료되지 않도록해야 함을 나타냅니다 :

import functools

@functools.lru_cache(maxsize=None)
def fib(num):
    if num < 2:
        return num
    else:
        return fib(num-1) + fib(num-2)

이 기능 자체는 매우 느리므로 시도해보십시오 fib(36). 약 10 초 정도 기다려야합니다.

lru_cache주석을 추가 하면 특정 값에 대해 함수가 최근에 호출 된 경우 해당 값을 다시 계산하지 않고 캐시 된 이전 결과를 사용합니다. 이 경우 코드 속도가 엄청나게 향상되는 반면 코드는 캐싱의 세부 사항으로 복잡하지 않습니다.


다른 답변은 그것이 무엇인지 잘 다룹니다. 나는 그것을 반복하지 않습니다. 당신에게 도움이 될만한 몇 가지 요점.

일반적으로 메모는 무언가를 계산하고 값이 비싼 모든 함수에 적용 할 수있는 작업입니다. 이 때문에 종종 데코레이터 로 구현됩니다 . 구현은 간단하며 다음과 같습니다.

memoised_function = memoise(actual_function)

또는 데코레이터로 표현

@memoise
def actual_function(arg1, arg2):
   #body

메모 화는 값 비싼 계산 결과를 유지하고 캐시 된 결과를 지속적으로 다시 계산하지 않고 반환합니다.

예를 들면 다음과 같습니다.

def doSomeExpensiveCalculation(self, input):
    if input not in self.cache:
        <do expensive calculation>
        self.cache[input] = result
    return self.cache[input]

더 자세한 설명은 메모 에 대한 위키 백과 항목에서 찾을 수 있습니다 .


hasattr손수 만들기를 원하는 사람들을 위해 내장 기능을 잊지 마십시오 . 이렇게하면 전역과 달리 함수 정의 내에 mem 캐시를 유지할 수 있습니다.

def fact(n):
    if not hasattr(fact, 'mem'):
        fact.mem = {1: 1}
    if not n in fact.mem:
        fact.mem[n] = n * fact(n - 1)
    return fact.mem[n]

나는 이것이 매우 유용하다는 것을 알았습니다.

def memoize(function):
    from functools import wraps

    memo = {}

    @wraps(function)
    def wrapper(*args):
        if args in memo:
            return memo[args]
        else:
            rv = function(*args)
            memo[args] = rv
            return rv
    return wrapper


@memoize
def fibonacci(n):
    if n < 2: return n
    return fibonacci(n - 1) + fibonacci(n - 2)

fibonacci(25)

메모 화는 기본적으로 재귀 알고리즘으로 수행 한 과거 작업의 결과를 저장하여 나중에 동일한 계산이 필요한 경우 재귀 트리를 통과 할 필요성을 줄입니다.

참조 http://scriptbucket.wordpress.com/2012/12/11/introduction-to-memoization/를

파이썬의 피보나치 메모 화 예제 :

fibcache = {}
def fib(num):
    if num in fibcache:
        return fibcache[num]
    else:
        fibcache[num] = num if num < 2 else fib(num-1) + fib(num-2)
        return fibcache[num]

메모 화는 함수를 데이터 구조로 변환하는 것입니다. 일반적으로 변환은 점진적이고 느리게 수행되기를 원합니다 (주어진 도메인 요소 또는 "키"의 요구에 따라). 게으른 기능적 언어에서이 게으른 변환은 자동으로 발생할 수 있으므로 메모를 (명시적인) 부작용없이 구현할 수 있습니다.


먼저 첫 부분에 답해야합니다. 메모 란 무엇입니까?

그것은 단지 시간 동안 메모리를 교환하는 방법 일뿐입니다. 생각 곱셈 표 .

파이썬에서 가변 객체를 기본값으로 사용하는 것은 일반적으로 나쁜 것으로 간주됩니다. 그러나 그것을 현명하게 사용한다면 실제로를 구현하는 것이 유용 할 수 있습니다 memoization.

다음은 http://docs.python.org/2/faq/design.html#why-are-default-values-shared-between-objects 에서 수정 된 예입니다.

dict함수 정의에서 변경 가능 사용 하여 중간 계산 결과를 캐시 할 수 있습니다 (예 : 계산 factorial(10)후 계산할 factorial(9)모든 중간 결과를 재사용 할 수 있음)

def factorial(n, _cache={1:1}):    
    try:            
        return _cache[n]           
    except IndexError:
        _cache[n] = factorial(n-1)*n
        return _cache[n]

다음은 목록 또는 dict 유형 인수로 작동하지 않는 솔루션입니다.

def memoize(fn):
    """returns a memoized version of any function that can be called
    with the same list of arguments.
    Usage: foo = memoize(foo)"""

    def handle_item(x):
        if isinstance(x, dict):
            return make_tuple(sorted(x.items()))
        elif hasattr(x, '__iter__'):
            return make_tuple(x)
        else:
            return x

    def make_tuple(L):
        return tuple(handle_item(x) for x in L)

    def foo(*args, **kwargs):
        items_cache = make_tuple(sorted(kwargs.items()))
        args_cache = make_tuple(args)
        if (args_cache, items_cache) not in foo.past_calls:
            foo.past_calls[(args_cache, items_cache)] = fn(*args,**kwargs)
        return foo.past_calls[(args_cache, items_cache)]
    foo.past_calls = {}
    foo.__name__ = 'memoized_' + fn.__name__
    return foo

handle_item에서 특별한 경우로 고유 한 해시 함수를 구현하여이 방법을 모든 객체로 자연스럽게 확장 할 수 있습니다. 예를 들어, 입력 인수로 집합을 취하는 함수에이 접근 방식을 적용하려면 handle_item에 추가 할 수 있습니다.

if is_instance(x, set):
    return make_tuple(sorted(list(x)))

inspect.getargspec을 사용하여 키워드 인수가 전달 된 순서와 상관없이 위치 및 키워드 인수와 함께 작동하는 솔루션 :

import inspect
import functools

def memoize(fn):
    cache = fn.cache = {}
    @functools.wraps(fn)
    def memoizer(*args, **kwargs):
        kwargs.update(dict(zip(inspect.getargspec(fn).args, args)))
        key = tuple(kwargs.get(k, None) for k in inspect.getargspec(fn).args)
        if key not in cache:
            cache[key] = fn(**kwargs)
        return cache[key]
    return memoizer

비슷한 질문 : 동등한 varargs 함수를 식별하면 파이썬에서 메모가 필요합니다.


cache = {}
def fib(n):
    if n <= 1:
        return n
    else:
        if n not in cache:
            cache[n] = fib(n-1) + fib(n-2)
        return cache[n]

이미 제공된 답변에 추가하기를 원했던 Python 데코레이터 라이브러리 에는 "해시 불가능한 유형"을 기억할 수있는 간단하면서도 유용한 구현이 있습니다 functools.lru_cache.

참고 URL : https://stackoverflow.com/questions/1988804/what-is-memoization-and-how-can-i-use-it-in-python



반응형