Web ページのプロファイルへのインターフェイスを提供するために、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