Skip to main content
 首页 » 编程设计

python之昂贵对象的高效池化/缓存

2025年05月04日9lvdongjie

我如何才能有效地在适当的 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,它具有许多不错的特性(清除缓存、跟踪命中/未命中统计信息、可选的大小和类型检查)