Rõ ràng, tìm kiếm nhanh mang lại một triệu lượt triển khai và hương vị của trình trang trí ghi nhớ bằng Python. Tuy nhiên, tôi quan tâm đến một hương vị mà tôi đã không thể tìm thấy. Tôi muốn có nó như vậy mà bộ nhớ cache của các giá trị được lưu trữ có thể có công suất cố định. Khi các phần tử mới được thêm vào, nếu đạt được dung lượng, thì giá trị cũ nhất sẽ bị loại bỏ và được thay thế bằng giá trị mới nhất.Làm cách nào để tạo một trình trang trí ghi nhớ bị chặn trong Python?
Quan tâm của tôi là, nếu tôi sử dụng tính năng ghi nhớ để lưu trữ nhiều yếu tố, thì chương trình sẽ bị lỗi do thiếu bộ nhớ. (Tôi không biết mối quan tâm này có thể được thực hiện tốt như thế nào.) Nếu bộ nhớ cache có kích thước cố định thì lỗi bộ nhớ sẽ không phải là vấn đề. Và nhiều vấn đề mà tôi làm việc khi thay đổi khi chương trình thực hiện để các giá trị được lưu trong bộ nhớ cache ban đầu trông rất khác so với các giá trị được lưu trong bộ nhớ cache sau này (và sẽ ít có khả năng tái diễn sau này). Đó là lý do tại sao tôi muốn những thứ lâu đời nhất được thay thế bởi những thứ mới nhất.
Tôi đã tìm thấy lớp OrderedDict
và ví dụ cho biết cách phân lớp nó để chỉ định kích thước tối đa. Tôi muốn sử dụng nó như là bộ nhớ cache của tôi, chứ không phải là một bình thường dict
. Vấn đề là, tôi cần trình trang trí ghi nhớ để tham số có tên là maxlen
mặc định là None
. Nếu nó là None
, thì bộ nhớ cache là vô hạn và hoạt động như bình thường. Bất kỳ giá trị nào khác được sử dụng làm kích thước cho bộ nhớ cache.
Tôi muốn nó hoạt động như sau:
@memoize
def some_function(spam, eggs):
# This would use the boundless cache.
pass
và
@memoize(200) # or @memoize(maxlen=200)
def some_function(spam, eggs):
# This would use the bounded cache of size 200.
pass
Dưới đây là đoạn code mà tôi có cho đến nay, nhưng tôi không thấy làm thế nào để vượt qua các tham số vào trang trí trong khi làm cho nó hoạt động cả hai "nude" và với một tham số.
import collections
import functools
class BoundedOrderedDict(collections.OrderedDict):
def __init__(self, *args, **kwds):
self.maxlen = kwds.pop("maxlen", None)
collections.OrderedDict.__init__(self, *args, **kwds)
self._checklen()
def __setitem__(self, key, value):
collections.OrderedDict.__setitem__(self, key, value)
self._checklen()
def _checklen(self):
if self.maxlen is not None:
while len(self) > self.maxlen:
self.popitem(last=False)
def memoize(function):
cache = BoundedOrderedDict() # I want this to take maxlen as an argument
@functools.wraps(function)
def memo_target(*args):
lookup_value = args
if lookup_value not in cache:
cache[lookup_value] = function(*args)
return cache[lookup_value]
return memo_target
@memoize
def fib(n):
if n < 2: return 1
return fib(n-1) + fib(n-2)
if __name__ == '__main__':
x = fib(50)
print(x)
Sửa: Sử dụng gợi ý của Ben, tôi đã tạo ra trang trí sau đây, mà tôi tin rằng hoạt động theo cách tôi tưởng tượng. Điều quan trọng với tôi là có thể sử dụng các chức năng được trang trí này với multiprocessing
và đó là một vấn đề trong quá khứ. Nhưng một thử nghiệm nhanh chóng của mã này dường như hoạt động chính xác, ngay cả khi nuôi công việc cho một nhóm các chủ đề.
def memoize(func=None, maxlen=None):
if func:
cache = BoundedOrderedDict(maxlen=maxlen)
@functools.wraps(func)
def memo_target(*args):
lookup_value = args
if lookup_value not in cache:
cache[lookup_value] = func(*args)
return cache[lookup_value]
return memo_target
else:
def memoize_factory(func):
return memoize(func, maxlen=maxlen)
return memoize_factory
Không hoàn toàn. Trong câu hỏi tôi đã hỏi một cái gì đó có thể làm việc tương đương với và không có tham số. Tôi không tin rằng người này có thể làm điều đó. – agarrett
Xin lỗi về điều đó, tôi đã chỉnh sửa câu trả lời của mình. – srgerg