Я нашел фрагмент кода памятки, и мне интересно, как он будет себя вести под copy.copy - PullRequest
2 голосов
/ 18 марта 2011

Я нашел этот замечательный декоратор, запоминающий:Проблема в том, что я выполняю применение операторов, возвращая copy.copy родительского состояния с примененным запрошенным оператором.Copy.copy экономит много времени, которое в противном случае было бы потрачено впустую, так как большая часть состояния идентична его родителю.

Теперь вот моя проблема.Если бы я использовал вышеупомянутый класс памятки внутри класса, будут ли переданы памятные копии функций, которые запоминают потенциально недопустимые значения?Я полагаю, что мне нужно как-то сделать недействительной запомненную копию.

Ответы [ 2 ]

1 голос
/ 18 марта 2011

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

Если вы делаете копию чего-либо и хотите, чтобы кэшированные значения в копииочистите, тогда вы должны очистить кеш явно.

Если вы действительно хотите, чтобы копии объекта не копировали кеш, то определите методы __copy__ или __deepcopy__ для управления копированием.(Обратите внимание, что обычно это используется для копирования базовых ресурсов, таких как дескрипторы файлов и дескрипторы.) Я не рекомендую делать это.

Вот пример обоих.

class memoized(object):
    """
    Decorator that caches a function's return value each time it is called.
    If called later with the same arguments, the cached value is returned, and
    not re-evaluated.
    """
    def __init__(self, func):
        self.func = func
        self.cache = {}
    def __copy__(self):
        """
        Don't copy the cache in a copy.
        """
        return memoized(self.func)
    def __deepcopy__(self, memo):
        """
        Don't copy the cache in a deep copy.
        """
        return memoized(self.func)

    def __call__(self, *args):
       try:
           return self.cache[args]
       except KeyError:
           value = self.func(*args)
           self.cache[args] = value
           return value
       except TypeError:
           # uncachable -- for instance, passing a list as an argument.
           # Better to not cache than to blow up entirely.
           return self.func(*args)
    def __repr__(self):
        """Return the function's docstring."""
        return self.func.__doc__
    def __get__(self, obj, objtype):
        """Support instance methods."""
        return functools.partial(self.__call__, obj)
    def clear_cache(self):
        self.cache = {}

@memoized
def fibonacci(n):
    "Return the nth fibonacci number."
    if n in (0, 1):
        return n
    return fibonacci(n-1) + fibonacci(n-2)

fibonacci(12)
print fibonacci.cache
fibonacci.clear_cache()
print fibonacci.cache

fibonacci(12)
print fibonacci.cache
import copy
f = copy.deepcopy(fibonacci)
print f.cache
1 голос
/ 18 марта 2011

Да. copy.copy неглубокий, поэтому он просто копирует ссылку на объект-оболочку памятки. Вы можете попробовать это так, если уберете метод __get__ из memoized (в противном случае вы получите объект partial, который используется для поддержки связанных методов):

class C(object):
    @memoized
    def foo(): pass

o1 = C()
o2 = copy.copy(o1)
print o1.foo.cache is o2.foo.cache

При необходимости вы можете создать новую оболочку (т.е. при копировании): memoized(C.foo.func).

...