有沒有辦法將一個函數的輸出記憶到磁盤?記憶到磁盤 - 蟒蛇 - 永久記憶
我有一個函數
def getHtmlOfUrl(url):
... # expensive computation
,很想做一些事情,如:
def getHtmlMemoized(url) = memoizeToFile(getHtmlOfUrl, "file.dat")
,然後調用getHtmlMemoized(URL),以便爲每個URL做昂貴的計算只有一次。
有沒有辦法將一個函數的輸出記憶到磁盤?記憶到磁盤 - 蟒蛇 - 永久記憶
我有一個函數
def getHtmlOfUrl(url):
... # expensive computation
,很想做一些事情,如:
def getHtmlMemoized(url) = memoizeToFile(getHtmlOfUrl, "file.dat")
,然後調用getHtmlMemoized(URL),以便爲每個URL做昂貴的計算只有一次。
Python提供了一個非常優雅的方式來做到這一點s - 裝飾者。基本上,裝飾器是一種函數,它包裝另一個函數以提供附加功能而不更改函數源代碼。你的裝飾可以這樣寫:
import json
def persist_to_file(file_name):
def decorator(original_func):
try:
cache = json.load(open(file_name, 'r'))
except (IOError, ValueError):
cache = {}
def new_func(param):
if param not in cache:
cache[param] = original_func(param)
json.dump(cache, open(file_name, 'w'))
return cache[param]
return new_func
return decorator
一旦你得到了,用@ -syntax「裝飾」的功能,你準備好了。
@persist_to_file('cache.dat')
def html_of_url(url):
your function code...
注意,該裝飾被有意簡化,可能不適用於所有情況,例如,當源函數接受或返回不能JSON序列化的數據。
更多關於裝飾:How to make a chain of function decorators?
下面是如何使裝飾保存緩存只有一次,在退出時間:
import json, atexit
def persist_to_file(file_name):
try:
cache = json.load(open(file_name, 'r'))
except (IOError, ValueError):
cache = {}
atexit.register(lambda: json.dump(cache, open(file_name, 'w')))
def decorator(func):
def new_func(param):
if param not in cache:
cache[param] = func(param)
return cache[param]
return new_func
return decorator
每次更新緩存時都會寫入一個新文件 - 取決於使用情況,這可能會(或可能不會)打敗加速你從記憶中獲得...... – root 2013-05-09 14:58:14
它*還*包含一個非常好的競爭條件,如果這個裝飾器同時使用,或者(更可能)以可重入的方式使用。如果'a()'和'b()'都被記憶,並且'a()'調用'b()',緩存可以被讀取爲'a()',然後再' ,第一個b的結果會被記憶,但是從調用過來的舊緩存會覆蓋它,b對緩存的貢獻將會丟失。 – SingleNegationElimination 2013-05-09 15:03:58
@root:當然,'atexit'可能是刷新緩存的好地方。另一方面,增加過早的優化可能會破壞此代碼的教育目的。 – georg 2013-05-09 15:25:27
這樣的事情應該做的事:
import json
class Memoize(object):
def __init__(self, func):
self.func = func
self.memo = {}
def load_memo(filename):
with open(filename) as f:
self.memo.update(json.load(f))
def save_memo(filename):
with open(filename, 'w') as f:
json.dump(self.memo, f)
def __call__(self, *args):
if not args in self.memo:
self.memo[args] = self.func(*args)
return self.memo[args]
基本用法:
your_mem_func = Memoize(your_func)
your_mem_func.load_memo('yourdata.json')
# do your stuff with your_mem_func
如果你想使用它後寫你「緩存」到一個文件 - 需要重新加載在未來:
your_mem_func.save_memo('yournewdata.json')
退房joblib.Memory
。這是一個完全做到這一點的圖書館。
只需三行代碼! :) – Andrew 2017-10-05 03:52:08
哇,這是一個偉大的圖書館!我無法相信我沒有joblib這麼多年。這應該是IMO的正確答案。 – foobarbecue 2017-10-29 04:31:55
Artemis library有一個這個模塊。 (你需要pip install artemis-ml
)
你裝飾你的函數:
from artemis.fileman.disk_memoize import memoize_to_disk
@memoize_to_disk
def fcn(a, b, c = None):
results = ...
return results
在內部,它通過這個哈希使哈希出的輸入參數和保存備忘文件。
假設你的數據JSON序列化,這個代碼應工作
import os, json
def json_file(fname):
def decorator(function):
def wrapper(*args, **kwargs):
if os.path.isfile(fname):
with open(fname, 'r') as f:
ret = json.load(f)
else:
with open(fname, 'w') as f:
ret = function(*args, **kwargs)
json.dump(ret, f)
return ret
return wrapper
return decorator
裝飾getHtmlOfUrl
,然後簡單地調用它,如果它之前已經運行,你會得到你的緩存數據。
經過與Python 2.x和蟒3.x的
一個清潔溶液搭載Python的擱置模塊。優點是緩存實時更新,這是例外證明。
import shelve
def shelve_it(file_name):
d = shelve.open(file_name)
def decorator(func):
def new_func(param):
if param not in d:
d[param] = func(param)
return d[param]
return new_func
return decorator
@shelve_it('cache.shelve')
def expensive_funcion(param):
pass
這將有助於函數被計算一次。接下來的後續調用相同的參數將返回存儲的結果。
只是pickle(或使用json)緩存字典。 – root 2013-05-09 14:02:34
謝謝,但我是一個蟒蛇新手(第二天)。我沒有絲毫的想法,你的意思是... – seguso 2013-05-09 14:04:05
好,所以你作爲一個新手做什麼是在谷歌查找「pickle python」,並回來給我們,如果你有任何問題。 – 2013-05-09 14:04:55