Useful decorator

P

Paul Rubin

In the course of writing a bunch of generator-oriented code I kept
wanting to temporarily truncate the output of generators for debugging,
i.e. I might have a function like

def generate_bazillion_items():
for line in bazillion_line_file:
yield itemify(line)

where I wanted to test the program on just the first 20 lines of the
file. After a number of rounds of editing the program to wrap an
xrange(20) loop I went to using islice(bazillion_line_file, 20), but
even more handy was to write this decorator:

def truncate(n):
from itertools import islice
def trunc(gen): # truncate generator to n items
return lambda *a,**kw: islice(gen(*a,**kw), n)
return trunc

Then to chop bazillion_items to 20 items, I just write:

@truncate(20)
def generate_bazillion_items():
for line in bazillion_line_file:
yield itemify(line)

When I want to run the whole file, I comment out the @truncate line,
and if I want to debug again, I just uncomment it.
 
J

James Stroud

Paul said:
In the course of writing a bunch of generator-oriented code I kept
wanting to temporarily truncate the output of generators for debugging,
i.e. I might have a function like

def generate_bazillion_items():
for line in bazillion_line_file:
yield itemify(line)

where I wanted to test the program on just the first 20 lines of the
file. After a number of rounds of editing the program to wrap an
xrange(20) loop I went to using islice(bazillion_line_file, 20), but
even more handy was to write this decorator:

def truncate(n):
from itertools import islice
def trunc(gen): # truncate generator to n items
return lambda *a,**kw: islice(gen(*a,**kw), n)
return trunc

Then to chop bazillion_items to 20 items, I just write:

@truncate(20)
def generate_bazillion_items():
for line in bazillion_line_file:
yield itemify(line)

When I want to run the whole file, I comment out the @truncate line,
and if I want to debug again, I just uncomment it.

Thes may be overkill, but how about allowing None as a parameter to
truncate, to allow for programmatic truncation?

# top of module
if DEBUG:
FILETRUNC = 20
else:
FILETRUNC = None

# imported, etc.
def truncate(n):
if n is None:
return lambda gen: gen
from itertools import islice
def trunc(gen): # truncate generator to n items
return lambda *a,**kw: islice(gen(*a,**kw), n)
return trunc

# in the body somewhere
@truncate(FILETRUNC)
def generate_bazillion_items():
# etc.

James
 
P

Paul McGuire

In the course of writing a bunch of generator-oriented code I kept
wanting to temporarily truncate the output of generators for debugging,
i.e. I might have a function like

def generate_bazillion_items():
for line in bazillion_line_file:
yield itemify(line)

where I wanted to test the program on just the first 20 lines of the
file. After a number of rounds of editing the program to wrap an
xrange(20) loop I went to using islice(bazillion_line_file, 20), but
even more handy was to write this decorator:

def truncate(n):
from itertools import islice
def trunc(gen): # truncate generator to n items
return lambda *a,**kw: islice(gen(*a,**kw), n)
return trunc

Then to chop bazillion_items to 20 items, I just write:

@truncate(20)
def generate_bazillion_items():
for line in bazillion_line_file:
yield itemify(line)

When I want to run the whole file, I comment out the @truncate line,
and if I want to debug again, I just uncomment it.

You should add this to the Python Wiki at http://wiki.python.org/moin/PythonDecoratorLibrary

-- Paul
 
S

Steven D'Aprano

Then to chop bazillion_items to 20 items, I just write:

@truncate(20)
def generate_bazillion_items():
for line in bazillion_line_file:
yield itemify(line)

When I want to run the whole file, I comment out the @truncate line,
and if I want to debug again, I just uncomment it.


By All-Father Wodan's one good eye! Why not do something like this?

if __debug__:
generate_bazillion_items = truncate(20)(generate_bazillion_items)

Now you don't have to comment/uncomment dozens of lines all over your
application, but only set a single global.
 
P

Paul Rubin

Steven D'Aprano said:
if __debug__:
generate_bazillion_items = truncate(20)(generate_bazillion_items)

Now you don't have to comment/uncomment dozens of lines all over your
application, but only set a single global.

The cool thing about organizing the program as a generator pipeline is
you only have to comment or uncomment one line ;).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top