在Python中记录一些函数参数

在Python中记录一些函数参数,python,caching,Python,Caching,假设我有一个函数,它接受一个表示web浏览器的对象,并使用它来抓取网页。我可能会在程序中的某个时候再次跟踪该URL,我更希望缓存该页面,而不是再次加载它。但诀窍是,此时我可能正在使用不同的浏览器对象。我很高兴能从缓存中获得这个值,但是LRuuCache(和大多数其他的记忆系统)会考虑到不同的浏览器参数不同的两个调用。我想知道是否有一种很好的方法可以在忽略一些函数参数的同时使用memonization。我下面得到的既不好也不可重复使用 from functools import lru_cache

假设我有一个函数,它接受一个表示web浏览器的对象,并使用它来抓取网页。我可能会在程序中的某个时候再次跟踪该URL,我更希望缓存该页面,而不是再次加载它。但诀窍是,此时我可能正在使用不同的浏览器对象。我很高兴能从缓存中获得这个值,但是LRuuCache(和大多数其他的记忆系统)会考虑到不同的浏览器参数不同的两个调用。我想知道是否有一种很好的方法可以在忽略一些函数参数的同时使用memonization。我下面得到的既不好也不可重复使用

from functools import lru_cache


class Browser(object):
    """Pretend this is a Browser from mechanize"""

    count = 0

    def __init__(self):
        self.count = Browser.count
        Browser.count += 1
        print("Created browser #{}".format(self.count))

    def get_url(self, url):
        """Pretend we're actually doing something here"""
        print("...Browser #{} visiting {}".format(self.count, url))
        return url[::-1] 


@lru_cache()
def _get_url(url):
    return _get_url.browser.get_url(url)
_get_url.browser = None


def get_url(browser, url):
    _get_url.browser = browser
    return _get_url(url)


for url in "www.python.org www.yahoo.com www.python.org".split():
    browser = Browser() # Imagine that we periodically switch to a different Browser instance
    print("{} => {}".format(url, get_url(browser, url)))
输出:

Created browser #0
...Browser #0 visiting www.python.org
www.python.org => gro.nohtyp.www
Created browser #1
...Browser #1 visiting www.yahoo.com
www.yahoo.com => moc.oohay.www
Created browser #2
www.python.org => gro.nohtyp.www

您可以使用
functools.partial
将浏览器转换为一元
get_url()
;这将防止您依赖模块范围的
\u get\u url\u浏览器
。这有效地绕过了
@lru\u cache
的限制,该限制是由包装函数的所有参数写入缓存的。@msw,我可以获取
get\u url
部分
,然后将
部分
馈送到
lru\u cache
。问题是当我需要切换到一个need
Browser
实例时该怎么办。我可以使用新的
浏览器创建新的
partial
,但是
lru\u缓存仍然指向旧的
partial
。我可以修改原始的
部分
对象以使用不同的
浏览器
,但这太糟糕了。是的,我同意。为新浏览器提供一个持久缓存实例将有助于获得更干净的结构。仔细想想,浏览器肯定应该有一个get_url()方法,它可以简单地检查缓存的条目或缓存它检索到的条目;这有效地使缓存成为隐藏的实现细节。换句话说,我希望我的浏览器能够生成页面,而不需要进行内部优化。您可以使用
functools.partial
将浏览器转换为一元
get_url()
;这将防止您依赖模块范围的
\u get\u url\u浏览器
。这有效地绕过了
@lru\u cache
的限制,该限制是由包装函数的所有参数写入缓存的。@msw,我可以获取
get\u url
部分
,然后将
部分
馈送到
lru\u cache
。问题是当我需要切换到一个need
Browser
实例时该怎么办。我可以使用新的
浏览器创建新的
partial
,但是
lru\u缓存仍然指向旧的
partial
。我可以修改原始的
部分
对象以使用不同的
浏览器
,但这太糟糕了。是的,我同意。为新浏览器提供一个持久缓存实例将有助于获得更干净的结构。仔细想想,浏览器肯定应该有一个get_url()方法,它可以简单地检查缓存的条目或缓存它检索到的条目;这有效地使缓存成为隐藏的实现细节。换句话说,我希望我的浏览器能够产生页面,而不需要进行内部优化。