2015-11-12 11 views
17

मैं स्मृति को लीक किए बिना कक्षाओं के अंदर functools lru_cache का उपयोग कैसे कर सकता हूं? निम्न न्यूनतम उदाहरण में foo उदाहरण जारी नहीं किया जाएगा, हालांकि दायरे से बाहर निकलना और कोई रेफरर नहीं है (lru_cache के अलावा)।कक्षा विधियों के साथ पाइथन functools lru_cache: रिलीज ऑब्जेक्ट

from functools import lru_cache 
class BigClass: 
    pass 
class Foo: 
    def __init__(self): 
     self.big = BigClass() 
    @lru_cache(maxsize=16) 
    def cached_method(self, x): 
     return x + 5 

def fun(): 
    foo = Foo() 
    print(foo.cached_method(10)) 
    print(foo.cached_method(10)) # use cache 
    return 'something' 

fun() 

लेकिन foo और इसलिए foo.big (एक BigClass) अभी भी जीवित

import gc; gc.collect() # collect garbage 
len([obj for obj in gc.get_objects() if isinstance(obj, Foo)]) # is 1 

इसका मतलब है कि फू/BigClass उदाहरणों अभी भी स्मृति में रह रहे हैं कर रहे हैं। Foo (डेल Foo) को हटाने से भी उन्हें रिहा नहीं किया जाएगा।

उदाहरण के लिए lru_cache क्यों हो रहा है? क्या कैश कुछ हैश का उपयोग नहीं करता है और वास्तविक वस्तु नहीं है?

कक्षाओं के अंदर lru_caches का अनुशंसित तरीका क्या है?

मैं दो तरीके दिए के बारे में पता: Use per instance caches या make the cache ignore object (जो गलत परिणाम को जन्म दे सकता है, हालांकि)

उत्तर

16

यह साफ समाधान नहीं है, लेकिन यह प्रोग्रामर के लिए पूरी तरह से पारदर्शी है:

import functools 
import weakref 

def memoized_method(*lru_args, **lru_kwargs): 
    def decorator(func): 
     @functools.wraps(func) 
     def wrapped_func(self, *args, **kwargs): 
      # We're storing the wrapped method inside the instance. If we had 
      # a strong reference to self the instance would never die. 
      self_weak = weakref.ref(self) 
      @functools.wraps(func) 
      @functools.lru_cache(*lru_args, **lru_kwargs) 
      def cached_method(*args, **kwargs): 
       return func(self_weak(), *args, **kwargs) 
      setattr(self, func.__name__, cached_method) 
      return cached_method(*args, **kwargs) 
     return wrapped_func 
    return decorator 

यह lru_cache के समान सटीक पैरामीटर लेता है, और बिल्कुल वही काम करता है। हालांकि यह self से lru_cache तक कभी नहीं गुजरता है और इसके बजाय प्रति-उदाहरण lru_cache का उपयोग करता है।

संबंधित मुद्दे