[Python-Dev] closure semantics
Guido van Rossum
guido at python.org
Wed Oct 22 13:57:18 EDT 2003
[Samuele]
> why exactly do we want write access to outer scopes?
>
> for completeness, to avoid the overhead of introducing a class here
> and there, to facilitate people using Scheme textbooks with Python?
Probably the latter; I think Jeremy Hylton does know more Scheme than
I do. :-)
> so far I have not been missing it,
>
> I don't find:
>
> 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).
Looking at the last example in the itertools docs:
def tee(iterable):
"Return two independent iterators from a single iterable"
def gen(next, data={}, cnt=[0]):
dpop = data.pop
for i in count():
if i == cnt[0]:
item = data[i] = next()
cnt[0] += 1
else:
item = dpop(i)
yield item
next = iter(iterable).next
return (gen(next), gen(next))
This would have been clearer if the author didn't have to resort to
representing his counter variable as a list of one element. Using
'global* x' to mean 'find x in an outer scope', and also moving data
into the outer scope, again to emphasize that it is shared between
multiple calls of gen() without abusing default arguments, it would
become:
def tee(iterable):
"Return two independent iterators from a single iterable"
data = {}
cnt = 0
def gen(next):
global* cnt
dpop = data.pop
for i in count():
if i == cnt:
item = data[i] = next()
cnt += 1
else:
item = dpop(i)
yield item
next = iter(iterable).next
return (gen(next), gen(next))
which is IMO more readable.
But in 2.4 this will become a real object implemented in C. :-)
--Guido van Rossum (home page: http://www.python.org/~guido/)
More information about the Python-Dev
mailing list