<p>给定一个函数,可以创建如下LazyComparer类:</p>
<pre><code>def lazy_func(func):
class LazyComparer(object):
def __init__(self, x):
self.x = x
def __lt__(self, other):
return func(self.x) < func(other.x)
def __eq__(self, other):
return func(self.x) == func(other.x)
return lambda x: LazyComparer(x)
</code></pre>
<p>要从多个函数中生成一个lazy key函数,可以创建一个实用函数:</p>
^{pr2}$
<p>它们一起使用可以这样:</p>
<pre><code>def countcalls(f):
"Decorator that makes the function count calls to it."
def _f(*args, **kwargs):
_f._count += 1
return f(*args, **kwargs)
_f._count = 0
return _f
@countcalls
def g(x): return x
@countcalls
def f1(x): return 0
@countcalls
def f2(x): return x
def report_calls(*funcs):
print(' | '.join(['{} calls to {}'.format(f._count, f.func_name)
for f in funcs]))
L = range(10)[::-1]
L.sort(key=make_lazy(f1, g))
report_calls(f1, g)
g._count = 0
L.sort(key=make_lazy(f2, g))
report_calls(f2, g)
</code></pre>
<p>它产生了</p>
<pre><code>18 calls to f1 | 36 calls to g
36 calls to f2 | 0 calls to g
</code></pre>
<p>上面的@countcalls修饰符用于确认当<code>f1</code>返回很多
对于ties,调用<code>g</code>来断开连接,但是当<code>f2</code>返回不同的值时,
<code>g</code>未被调用。在</p>
<hr/>
<p>NPE的解决方案在<code>Key</code>类中添加了记忆。有了上面的解决方案,
您可以在<code>LazyComparer</code>类之外(独立于)添加备忘录:</p>
<pre><code>def memo(f):
# Author: Peter Norvig
"""Decorator that caches the return value for each call to f(args).
Then when called again with same args, we can just look it up."""
cache = {}
def _f(*args):
try:
return cache[args]
except KeyError:
cache[args] = result = f(*args)
return result
except TypeError:
# some element of args can't be a dict key
return f(*args)
_f.cache = cache
return _f
L.sort(key=make_lazy(memo(f1), memo(g)))
report_calls(f1, g)
</code></pre>
<p>从而减少了对<code>g</code>的调用:</p>
<pre><code>10 calls to f1 | 10 calls to g
</code></pre>