有效汇集/缓存昂贵的对象

时间:2012-08-03 11:03:43

标签: python

如何在数据库中保存昂贵答案的适当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个对象,以访问数据库中的某些值barFoo.bar属性表示昂贵的操作,因此是惰性处理。 Foo类的实例根本没有太大变化,它们只是数据库存储数据的读代理。

现在我意识到,具有相同Foo的{​​{1}}个实例经常被创建和销毁。每次对象死亡时,id的知识都会丢失,必须在以后再次从数据库中获取。

我想出了两种方法来处理它,或者自己汇集对象:

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):
    ...

是否有一些更好,更pythonic的解决方案?我监督了什么吗?

PS:我是Python初学者,具有Java / C ++背景。

2 个答案:

答案 0 :(得分:1)

我会使用一个简单的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,它具有许多不错的功能(清除缓存,跟踪命中/未命中统计信息,可选大小和类型检查)

答案 1 :(得分:0)