我正在编写一个解析 HTML 的类,以便为网页上的配置文件提供接口。它看起来像这样:
class Profile(BeautifulSoup):
def __init__(self, page_source):
super().__init__(page_source)
def username(self):
return self.title.split(':')[0]
除了更复杂和耗时。因为我知道底层配置文件在Profile
对象的生命周期内不会发生变化,所以我认为这将是一个缓存结果的好地方,以避免重新计算已知的值。我用装饰器实现了这个,结果如下所示:
def cached_resource(method_to_cache):
def decorator(self, *args, **kwargs):
method_name = method_to_cache.__name__
try:
return self._cache[method_name]
except KeyError:
self._cache[method_name] = method_to_cache(self, *args, **kwargs)
return self._cache[method_name]
return decorator
class Profile(BeautifulSoup):
def __init__(self, page_source):
super().__init__(page_source)
self._cache = {}
@cached_resource
def username(self):
return self.title.split(':')[0]
当我将此代码提供给 pylint 时,它抱怨cached_resource
可以访问客户端类的受保护变量。
我意识到公共和私有之间的区别在 Python 中并不是什么大问题,但我仍然很好奇——我在这里做了什么坏事吗?让装饰器依赖与它们关联的类的实现细节是不是很糟糕?
编辑:我不清楚邓肯答案中的关闭是如何工作的,所以也许这有点混乱,但这会是一个更简单的解决方案吗?
def cached_resource(method_to_cache):
def decorator(self, *args, **kwargs):
method_name = method_to_cache.__name__
try:
return self._cache[method_name]
except KeyError:
self._cache[method_name] = method_to_cache(self, *args, **kwargs)
except AttributeError:
self._cache = {}
self._cache[method_name] = method_to_cache(self, *args, **kwargs)
finally:
return self._cache[method_name]
return decorator