我如何才能有效地在适当的 pythonic 池/缓存对象中保存来自数据库的昂贵答案?
我的模块包含以下原理图代码:
import sqlite3
db = sqlite3.connect(config.DB) # application shared database
db.row_factory = sqlite3.Row
class Foo:
def __init__(self, id):
self.id = id
@property
def bar(self):
if not hasattr(self, '_bar'):
row = db.execute(
'SELECT bar FROM bars WHERE id=?', (self.id, )).fetchone()
self._bar = row['bar'] if row else None
return self._bar
应用程序在其生命周期内创建 Foo 对象以访问数据库中的某些值 bar。 Foo.bar 属性代表一个昂贵的操作,因此是惰性处理。 Foo 类的实例根本没有太大变化,它们只是数据库存储数据的读取代理。
现在我意识到,具有相同 id 的 Foo 实例经常被创建和销毁。每次对象死亡时,Foo.bar 的知识都会丢失,并且稍后必须再次从数据库中获取。
我想出了两种方法来处理它,要么自己池化对象:
class DBObject:
_pool = {}
def __new__(cls, *params, **key_params):
key = cls.__name__ + str(params) + str(key_params)
if not key in DBObject._pool:
self = object.__new__(cls, *params, **key_params)
DBObject._pool[key] = self
self = DBObject._pool[key]
return self
class Foo(DBObject):
...
或者他们的状态:
class DBObject:
_states = {}
def __new__(cls, *params, **key_params):
self = object.__new__(cls, *params, **key_params)
key = cls.__name__ + str(params) + str(key_params)
if not key in DBObject._states:
DBObject._states[key] = {}
self.__dict__ = DBObject._states[key]
return self
class Foo(DBObject):
...
有没有更好更pythonic的解决方案?我监督了什么吗?
PS:我是 Python 初学者,有 Java/C++ 背景。
请您参考如下方法:
我会使用一个简单的 memoize 装饰器,这是一个通用的装饰器:
import functools
def memoize(func):
cache = {}
sentinel = object()
@functools.wraps(func)
def wrapper(*args, **kwargs):
key = (args, tuple(kwargs.items()))
result = cache.get(key, sentinel)
if result is not sentinel:
return result
result = func(*args, **kwargs)
cache[key] = result
return result
return wrapper
你可以用它来装饰 Foo 类:
@memoize
class Foo:
...
您还可以将 memoize 装饰器应用于 bar 方法,并稍微清理一下:
@property
@memoize
def bar(self):
row = db.execute('SELECT bar FROM bars where id=?', (self.id, )).fetchone()
return row['bar'] if row else None
Python3.2 中的另一个新特性是 functools.lru_cache,它具有许多不错的特性(清除缓存、跟踪命中/未命中统计信息、可选的大小和类型检查)
