2013-02-18 38 views
23

Sử dụng trang trí LRU cache tìm thấy ở đây: http://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python-33s-lru-cache/Python LRU cache Decorator mỗi Instance

from lru_cache import lru_cache 
class Test: 
    @lru_cache(maxsize=16) 
    def cached_method(self, x): 
     return x + 5 

tôi có thể tạo ra một phương pháp học được trang trí với điều này nhưng nó kết thúc việc tạo ra một bộ nhớ cache toàn cầu áp dụng cho tất cả trường của lớp Test. Tuy nhiên, ý định của tôi là tạo một bộ nhớ cache cho từng trường hợp. Vì vậy, nếu tôi đã thực hiện 3 bài kiểm tra, tôi sẽ có 3 bộ nhớ cache LRU thay vì 1 bộ nhớ cache LRU cho cả 3 trường hợp. Chỉ có một dấu hiệu duy nhất cho thấy điều này đang xảy ra là khi gọi cache_info() trên các phương thức trang trí lớp khác nhau, tất cả đều trả về cùng một số liệu thống kê bộ đệm (rất khó xảy ra khi chúng được tương tác với rất khác nhau). đối số):

CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128) 
CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128) 
CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128) 

Có một trình trang trí hoặc thủ thuật cho phép tôi dễ dàng khiến trình trang trí này tạo bộ nhớ cache cho từng cá thể lớp không?

+1

Hãy nhớ rằng, một trang trí chỉ là cú pháp đường cho phương thức 'def: pass; method = decorate (phương pháp) '. Vì vậy, bạn có thể dịch máy móc này để tạo phương pháp được trang trí trong '__init__' của bạn. –

+0

Bạn có chắc chắn rằng bạn biết "phương pháp lớp" là gì? Bởi vì tôi nghĩ bạn tìm kiếm một phương pháp bình thường. Nếu một phương thức lớp là một cá thể cụ thể, theo định nghĩa, một phương thức bình thường của một cá thể. Hoặc tại sao chính xác bạn thậm chí cần một phương pháp lớp học? Hoặc tại sao bạn muốn một bộ nhớ cache "cho mỗi trường hợp"? – Mayou36

Trả lời

28

Giả sử bạn không muốn sửa đổi mã (ví dụ: bởi vì bạn muốn có thể chỉ cổng đến 3,3 và sử dụng lệnh stdlib functools.lru_cache hoặc sử dụng functools32 ngoài PyPI thay vì sao chép và dán công thức vào mã của bạn), có một giải pháp hiển nhiên: Tạo một phương thức thể hiện được trang trí mới với từng trường hợp.

class Test: 
    def cached_method(self, x): 
     return x + 5 
    def __init__(self): 
     self.cached_method = lru_cache(maxsize=16)(self.cached_method) 
+1

Tuyệt vời. Nhưng làm thế nào tôi có thể làm điều này cho một @property chỉ nhận được? – Gilly

2

Làm thế nào về điều này: một chức năng trang trí mà kết thúc tốt đẹp phương pháp với lru_cache lần đầu tiên nó được gọi là trên mỗi trường hợp?

def instance_method_lru_cache(*cache_args, **cache_kwargs): 
    def cache_decorator(func): 
     @wraps(func) 
     def cache_factory(self, *args, **kwargs): 
      print('creating cache') 
      instance_cache = lru_cache(*cache_args, **cache_kwargs)(func) 
      instance_cache = instance_cache.__get__(self, self.__class__) 
      setattr(self, func.__name__, instance_cache) 
      return instance_cache(*args, **kwargs) 
     return cache_factory 
    return cache_decorator 

Sử dụng nó như thế này:

class Foo: 
    @instance_method_lru_cache() 
    def times_2(self, bar): 
     return bar * 2 

foo1 = Foo() 
foo2 = Foo() 

print(foo1.times_2(2)) 
# creating cache 
# 4 
foo1.times_2(2) 
# 4 

print(foo2.times_2(2)) 
# creating cache 
# 4 
foo2.times_2(2) 
# 4 

Here's a gist on GitHub với một số tài liệu nội tuyến.

Các vấn đề liên quan