2

如何有效地在适当的 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根本没有太大变化,它们只是数据库存储数据的读取代理。

现在我意识到,Foo具有相同实例的实例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):
    ...

或他们的状态:

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:我是具有 Java/C++ 背景的 Python 初学者。

4

2 回答 2

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

于 2012-08-03T11:36:47.220 回答
0

lru lfu 缓存实现为装饰器

于 2012-08-03T11:30:46.727 回答