Python 高手编程系列五百一十九:缓存

缓存装饰器与参数检查十分相似,不过它重点是关注那些内部状态不会影响输出的函数。
每组参数都可以链接到唯一的结果。这种编程风格是函数式编程(functional programming,参
见 https://en.wikipedia.org/wiki/Functional_programming)的特点,当输入值有限时可以使用。
因此,缓存装饰器可以将输出与计算它所需要的参数放在一起,并在后续的调用中直
接返回它。这种行为被称为 memoizing(参见 https://en.wikipedia.org/wiki/Memoization),
很容易被实现为一个装饰器:
import time
import hashlib
import pickle
cache = {}
def is_obsolete(entry, duration):
return time.time() - entry[‘time’] > duration
def compute_key(function, args, kw):
key = pickle.dumps((function.name, args, kw))
return hashlib.sha1(key).hexdigest()
def memoize(duration=10):
def _memoize(function):
def __memoize(*args, **kw):
key = compute_key(function, args, kw)

是否已经拥有它了?

if (key in cache and
not is_obsolete(cache[key], duration)):
print(‘we got a winner’)
return cache[key][‘value’]

计算

result = function(*args, **kw)

保存结果

cache[key] = {
‘value’: result,
‘time’: time.time()
}
return result
return __memoize
return _memoize
利用已排序的参数值来构建 SHA 哈希键,并将结果保存在一个全局字典中。利用 pickle
来建立 hash,这是冻结所有作为参数传入的对象状态的快捷方式,以确保所有参数都满足
要求。举个例子,如果用一个线程或套接字作为参数,那么会引发 PicklingError(参
见 https://docs.python.org/3/library/pickle.html)。duration 参数的作用是,如果上一次函数
调用已经过去了太长时间,那么它会使缓存值无效。
下面是一个使用示例:

@memoize()
… def very_ very very complex stuff(a, b):
… # 如果在执行这个计算时计算机过热
… # 请考虑中止程序
… return a + b

very
very very complex stuff(2, 2)
4
very
very very complex stuff(2, 2)
we got a winner
4
@memoize(1) # 1 秒后令缓存失效
… def very
very very complex stuff(a, b):
… return a + b

very
very very complex stuff(2, 2)
4
very
very very complex stuff(2, 2)
we got a winner
4
cache
{‘c2727f43c6e39b3694649ee0883234cf’: {‘value’: 4, ‘time’:
1199734132.7102251)}
time.sleep(2)
very
very very complex _stuff(2, 2)
4
缓存代价高昂的函数可以显著提高程序的总体性能,但必须小心使用。缓存值还可以
与函数本身绑定,以管理其作用域和生命周期,代替集中化的字典。但在任何情况下,更
高效的装饰器会使用基于高级缓存算法的专用缓存库。
代理
代理装饰器使用全局机制来标记和注册函数。举个例子,一个根据当前用户来保护代
码访问的安全层可以使用集中式检查器和相关的可调用对象要求的权限来实现:
class User(object):
def init(self, roles):
self.roles = roles
class Unauthorized(Exception):
pass
def protect(role):
def _protect(function):
def __protect(*args, **kw):
user = globals().get(‘user’)
if user is None or role not in user.roles:
raise Unauthorized(“I won’t tell you”)
return function(*args, **kw)
return __protect
return protect
这一模型常用于 Python Web 框架中,用于定义可发布类的安全性。例如,Django 提供
装饰器来保护函数访问的安全。
下面是一个示例,当前用户被保存在一个全局变量中。在方法被访问时装饰器会检查
他/她的角色:
tarek = User((‘admin’, ‘user’))
bill = User((‘user’,))
class MySecrets(object):
… @protect(‘admin’)
… def waffle
recipe(self):
… print(‘use tons of butter!’)

these
_are = MySecrets()
user = tarek

these_ are.waffle recipe()
use tons of butter!
user = bill
these
are.waffle _recipe()
Traceback (most recent call last):
File “”, line 1, in
File “”, line 7, in wrap
__main __.Unauthorized: I won’t tell you

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值