On Wednesday 22 October 2003 07:57 pm, Guido van Rossum wrote: ...
def accgen(n): def acc(i): global n in accgen n += i return n return acc
particulary more compelling than:
class accgen: def __init__(self, n): self.n = n
def __call__(self, i): self.n += i return self.n
Some people have "fear of classes". Some people think that a function's scope can be cheaper than an object (someone should time this).
I need to simulate the "rebinding name in outer scope" with some kind of item or attribute, of course, but, given this, here comes:
given this b.py:
def accgen_attr(n): def acc(i): acc.n += i return acc.n acc.n = n return acc
def accgen_item(n): n = [n] def acc(i): n += i return n return acc
class accgen_clas(object): def __init__(self, n): self.n = n def __call__(self, i): self.n += i return self.n
def looper(accgen, N=1000): acc = accgen(100) x = map(acc, xrange(N)) return x
[alex@lancelot ext]$ timeit.py -c -s'import b' 'b.looper(b.accgen_attr)' 1000 loops, best of 3: 1.86e+03 usec per loop
[alex@lancelot ext]$ timeit.py -c -s'import b' 'b.looper(b.accgen_item)' 1000 loops, best of 3: 1.18e+03 usec per loop
[alex@lancelot ext]$ timeit.py -c -s'import b' 'b.looper(b.accgen_clas)' 100 loops, best of 3: 2.1e+03 usec per loop
So, yes, a function IS slightly faster anyway (accgen_attr vs accgen_clas), AND simulating outer-scope-rebinding with a list item is somewhat faster than doing so with an attr (a class always uses an attr, and most of its not-too-terrible performance handicap presumably comes from that fact).
I just don't think such closures would typically be used in bottlenecks SO tight that a 10%, or even a 40%, extra overhead are going to be crucial. So, I find it hard to get excited either way by this performance issue.