http://pythonprogramming.jottit.com/functional_programming 有一个教程,它给出了一个如何使用高阶函数返回函数的示例:
def trace(f):
f.indent = 0
def g(x):
print '| ' * f.indent + '|--', f.__name__, x
f.indent += 1
value = f(x)
print '| ' * f.indent + '|--', 'return', repr(value)
f.indent -= 1
return value
return g
和
def memoize(f):
cache = {}
def g(x):
if x not in cache:
cache[x] = f(x)
return cache[x]
return g
但我不明白它如何能够在语句上的同一变量上分配两个函数:
fib = trace(fib)
fib = memoize(fib)
print fib(4)
跟踪和记忆似乎都对最后一次调用有影响。为什么?
你写的非常类似于
fib2 = memoize(trace(fib))
print fib2(4)
因为您在调用 trace
后更改了变量fib
指向哪个函数,因此memoize
应用于跟踪版本(然后再次"覆盖"fib
)。
如果要分别拥有跟踪版本和记忆版本,则需要将它们的结果分配给不同的变量,例如:
fib_trace = trace(fib)
fib_memo = memoize(fib)
print fib_trace(4), fib_memo(4)
trace()
和 memoize()
创建一个新的函数对象并将其返回给您。
在每种情况下,新函数对象都会"包装"旧函数对象,因此原始函数不会丢失。
使用我惊人的ASCII艺术技巧,这是一个图表:
f(x) # this is your original function
trace(f(x)) # trace "wraps" it and returns a wrapped object
memoize(trace(f(x))) # memoize "wraps" it and returns a new wrapped function object
我们从一个绑定到名称 fib
的函数对象开始。
然后我们调用 trace(fib)
创建一个新的函数对象。 首次创建时,它的名称是g
,但随后我们将其绑定到名称 fib
. 尝试打印fib.__name__
。
然后我们调用 memoize(fib)
创建一个新的函数对象。 同样,它首先以 g
的名称创建,但随后绑定到名称 fib
.
请记住,在 Python 中,一切都是对象,对象可以没有名称、一个名称或多个名称存在。 在这种情况下,我们不断重用名称fib
但我们不断将其与不同的函数对象重新绑定。
它与:
a = a + 2
a = a + 5
print a
正如a
将增加 7 一样,fib
将同时应用两个装饰器。