473,378 Members | 1,343 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,378 software developers and data experts.

Callbacks to generators

Is there a straightforward way to create a generator from a function that
takes a callback? For instance, I have a function called "process":

def process(text, on_token):
...

For each token that "process" finds in "text", it creates a token object,
"token", and calls "on_token(token)".

Now, suppose I wanted to create a generator based on this function. I tried
to do the following:

def process_iter(text):
def on_token(token):
yield token
process(text, on_token)

However, rather than create a generator as I had hoped, this function
doesn't return anything. I guess it creates a bunch of singleton generators,
one per token, and throws them away. In any case, is there a way to do what
I am trying to do here without resorting to threads?

The reason I am trying to do this is that I'd still like to be able to use
"process" in code for Python 2.1, which does not support generators. I'd
like to avoid implementing the entire thing twice or basing the callback
version on the generator version.

Thanks,
Dave

--
..:[ dave benjamin: ramen/[sp00] -:- spoomusic.com -:- ramenfest.com ]:.
: i'm half drunk on babble you transmit - soul coughing / true dreams :
Jul 18 '05 #1
5 1345
Dave Benjamin wrote:
Is there a straightforward way to create a generator from a function that
takes a callback? For instance, I have a function called "process":
Last time I asked there wasn't.
The reason I am trying to do this is that I'd still like to be able to use
"process" in code for Python 2.1, which does not support generators. I'd
like to avoid implementing the entire thing twice or basing the callback
version on the generator version.


When you know beforehand that your code should play nice with both the
visitor and the iterator pattern, you can use an iterator class instead of
a generator, e. g:

try:
iter
except NameError:
# prepare for the poor man's generator...
class StopIteration(Exception):
pass

def iter(seq):
try:
seq.__iter__
except AttributeError:
pass
else:
return seq.__iter__()
# test for as many special cases as you like, e. g.
if isinstance(seq, type([])):
return ListIterator(seq)
raise TypeError

hasGenerators = 0
else:
hasGenerators = 1

# this is clumsy...
class ListIterator:
""" Example of an iterator class """
def __init__(self, seq):
self.seq = seq
self.index = 0

def __iter__(self):
return self

def next(self):
index = self.index
self.index += 1
try:
return self.seq[index]
except IndexError:
raise StopIteration

def visit(seq, visitor):
it = iter(seq)
try:
while 1:
visitor(it.next())
except StopIteration:
pass

# ... but leaves client code unaffected:
if hasGenerators:
print "using generator"
for item in range(3):
print 2 * item,
print

def printItem(item):
print 2 * item,

print "using visitor"
visit(range(3), printItem)
print

Peter
Jul 18 '05 #2

"Dave Benjamin" <ra***@lackingtalent.com> wrote in message
news:slrncca3pe.6qh.ra***@lackingtalent.com...
Is there a straightforward way to create a generator from a function that
takes a callback? For instance, I have a function called "process":
This sentence is not clear *to me*, as written, so I respond to how I
interpret it, in light of process_iter below.
def process(text, on_token):
...
For each token that "process" finds in "text", it creates a token object,
"token", and calls "on_token(token)".
I think your fundamental problem is that callbacks usually have an
item-to-process parameter, as with on_token above, whereas iterator.next
methods do not. So you would have to use a token communicating method that
both types of responders can use.
Now, suppose I wanted to create a generator based on this function. I tried to do the following:

def process_iter(text):
def on_token(token):
yield token
process(text, on_token)
This on_token is a generator function. When called, it returns a generator
whose next method would yield token if it were to be called, but which
never is called.
However, rather than create a generator as I had hoped, this function
Not sure whether 'this function' means process_iter, which creates a
generator function on_token and passes it to process(), or on_token itself,
which does create a generator each time it is called within process.
doesn't return anything. I guess it creates a bunch of singleton generators, one per token, and throws them away.
Correct. I *think* what you want is something more like

#select one on following depending on Python version

def on_token(): # modified traditional call_back
token = <get token from token_stash>
return <some func of token>

def on_token_gen(): # generator version for 2.2+
while 1:
token = <get token from token_stash>
yield <some func of token>
on_token = on_token_gen().next

process(text, on_token)

where process puts token in token_stash before calling on_token()
In any case, is there a way to do what
I am trying to do here without resorting to threads?


Does above help?

Terry J. Reedy


Jul 18 '05 #3
> def process(text, on_token):
...

For each token that "process" finds in "text", it creates a token object,
"token", and calls "on_token(token)".

Now, suppose I wanted to create a generator based on this function. I tried to do the following:

def process_iter(text):
def on_token(token):
yield token
process(text, on_token)

However, rather than create a generator as I had hoped, this function
doesn't return anything. I guess it creates a bunch of singleton generators, one per token, and throws them away. In any case, is there a way to do what I am trying to do here without resorting to threads?


Something weird here. I hven't used generators much, but seems to me that:

1) you maybe don't need them:

def process_iter(text):
def on_token(token):
return token
process(text, on_token)

2) you need some sort of while loop so the fnction doesn't return after the
first yield:

def process_iter(text):
def on_token(token):
while 1:
yield token
process(text, on_token)

I'm curious to understand if neither of those are true, why...

Oliver
Jul 18 '05 #4

"Humpty Dumpty" <ol***************@utoronto.ca> wrote in message
news:_Z********************@news20.bellglobal.com. ..
Something weird here. I hven't used generators much, but seems to me that:
1) you maybe don't need them:

def process_iter(text):
def on_token(token):
return token
process(text, on_token)
True. And one cannot use them for 2.1. I expect OP wants to use iterators
in 2.2+ to avoid repeated function call overhead. The main problem is
writing code that works both ways.
2) you need some sort of while loop so the fnction doesn't return after the first yield:
True. however...
def process_iter(text):
def on_token(token):
while 1:
yield token


This is garbled and repeats OP's mistake of making token a param of the
generator function. A generator function is called once and its parameter
is used to set up the generator whose next method is what gets called
repeatedly. See my previous post for a possibly workable example.

Terry J. Reedy


Jul 18 '05 #5

"Terry Reedy" <tj*****@udel.edu> wrote in message
news:ca**********@sea.gmane.org...
#select one on following depending on Python version

def on_token(): # modified traditional call_back
token = <get token from token_stash>
return <some func of token>

def on_token_gen(): # generator version for 2.2+
while 1:
token = <get token from token_stash>
yield <some func of token>
on_token = on_token_gen().next

process(text, on_token)

where process puts token in token_stash before calling on_token()


If doing lots of callbacks, repeating anything like the above for each
would get pretty tedious. So after getting the pattern correct, if the
above does indeed work, I might try to factor out the common portion and
write a callback factory function that inserts the variable code into the
version-appropriate template, compiles it, and returns the
version-apprieate callback.

Terry J. Reedy


Jul 18 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

23
by: Francis Avila | last post by:
Below is an implementation a 'flattening' recursive generator (take a nested iterator and remove all its nesting). Is this possibly general and useful enough to be included in itertools? (I know...
9
by: Francis Avila | last post by:
A little annoyed one day that I couldn't use the statefulness of generators as "resumable functions", I came across Hettinger's PEP 288 (http://www.python.org/peps/pep-0288.html, still listed as...
3
by: Paul Moore | last post by:
I'm trying to check a graph (represented in the usual Python adjacency list format) for loops. This is dead simple - you use a depth-first search, and look out for "back edges" (edges from a vertex...
1
by: Melissa Wallis | last post by:
I have a class with 5 callbacks. Two of the callbacks work fine but the others don't. The main difference is that the callbacks that don't work are composed of a sequence of structs. I noticed a...
3
by: Carlos Ribeiro | last post by:
As a side track of my latest investigations, I began to rely heavily on generators for some stuff where I would previsouly use a more conventional approach. Whenever I need to process a list, I'm...
3
by: Michael Sparks | last post by:
Hi, I'm posting a link to this since I hope it's of interest to people here :) I've written up the talk I gave at ACCU Python UK on the Kamaelia Framework, and it's been published as a BBC...
5
by: Christopher Jastram | last post by:
I'm a self-taught programmer, so this might be a pretty dumb question. If it is, please point me in the right direction and I shall apologize profusely. I have a question regarding C++ and...
6
by: Talin | last post by:
I've been using generators to implement backtracking search for a while now. Unfortunately, my code is large and complex enough (doing unification on math expressions) that its hard to post a...
13
by: Martin Sand Christensen | last post by:
Hi! First a bit of context. Yesterday I spent a lot of time debugging the following method in a rather slim database abstraction layer we've developed: ,---- | def selectColumn(self,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.