memo pythonでの部分適用
functools.partialの存在意義が分からなかった。
lambdaで包んで返せばそれで良いと思っていた。
勘違いしていた。
確かに、functools.partialは便利だ。
def f(x): def _f(): return x + 1 return _f xs = [f(x) for x in xrange(10)] print [x() for x in xs] g = lambda x : lambda : x + 1 ys = [g(x) for x in xrange(10)] print [y() for y in ys] zs = [lambda : x + 1 for x in xrange(10)] print [z() for z in zs] # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
(let1 r '() (let1 xs (iota 10) (while (not (null? xs)) (push! r (lambda () (or (null? xs) (+ (car xs) 1)))) (pop! xs))) (map (lambda (f) (f)) r)) ; => (#t #t #t #t #t #t #t #t #t #t) ;; 間違い ;; (let1 r '() ;; (let1 xs (iota 10) ;; (while (not (null? xs)) ;; (push! r (lambda () (+ (car xs) 1))) ;; (pop! xs))) ;; (map (lambda (f) (f)) xs)) ; => (10 9 8 7 6 5 4 3 2 1) (let1 r '() (let1 i 0 (while (<= i 10) (push! r (lambda () (+ i 1))) (inc! i))) (map (lambda (f) (f)) r)) ; => (12 12 12 12 12 12 12 12 12 12 12)
functools.partial
from functools import partial def adder(x, y): return x + y xs = [lambda y : adder(x, y) for x in xrange(10)] print [fn(0) for fn in xs] zs = [partial(adder, z) for z in xrange(10)] print [fn(0) for fn in zs] # [9, 9, 9, 9, 9, 9, 9, 9, 9, 9] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
追記
これがうまくいくのは再帰呼び出しのスタックで参照先が異なるからということで理由は分かる。
def loop(n): r = [] def rec(i): if i >= n: return r.append(lambda : i + 1) rec(i + 1) rec(0) return r xs = loop(10) print [x() for x in xs] # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]