Welcome, guest | Sign In | My Account | Store | Cart

Alternative notation for defining closures in python; It avoids packing closure variables into containers by assigning attributes to the inner function.

Python, 28 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# nice and clean closure notation
def get_counter_neat():
    def f():
        f.x += 1
        return f.x
    f.x = 0
    return f

# traditional, not_so_neat closure notation
def get_counter_traditional():
    x = [0]
    def f():
        x[0] += 1
        return x[0]
    return f

#### EXAMPLE ###########################################################

cnt_a = get_counter_neat()
cnt_b = get_counter_neat()

print cnt_a()   # >>> 1
print cnt_a()   # >>> 2
print cnt_a()   # >>> 3
print cnt_b()   # >>> 1
print cnt_a()   # >>> 4
print cnt_b()   # >>> 2
print cnt_b()   # >>> 3

3 comments

Matt Good 15 years, 9 months ago  # | flag

Updating closure variables. I think it's worth noting that this also makes it easy to update the closure variables since they're attributes of the function:

>>> cnt_a = get_counter_neat()
>>> cnt_a()
1
>>> cnt_a()
2
>>> cnt_a.x = 10
>>> cnt_a()
11
bearophile - 15 years, 8 months ago  # | flag

Possible fix. Probably this is what you want:

cnt_a = get_counter_neat()

cnt_b = get_counter_traditional()

bluecamel 11 years, 7 months ago  # | flag

I'm curious why you wouldn't just use a class:

class counter:
  def __init__(self):
    self.x = 0

  def __call__(self):
    self.x += 1
    return self.x

cnt_a = counter() # works exactly like all of the other examples, and you have access to cnt_a.x, etc...

It's also just as easy to specify starting and increment values:

class counter:
  def __init__(self, start = 0, inc = 1):
    self.x = start - inc
    self.inc = inc

  def __call__(self):
    self.x += self.inc
    return self.x

a = counter(10, 10) # create a counter starting at 10, incrementing by 10 each time
print a() # prints 10
print a() # prints 20
Created by Maciej Obarski on Tue, 7 Mar 2006 (PSF)
Python recipes (4591)
Maciej Obarski's recipes (6)

Required Modules

  • (none specified)

Other Information and Tasks