Prev: Checker 1.3 Released!
Next: Weird Python behaviour
From: Santiago Caracol on 10 Aug 2010 06:34 Hello, I want to write a web application that does this: (1) The user submits a query: --------------------------------- | What is the answer? | --------------------------------- <Submit> (2) The web server gives the user N answers and a button saying "More answers": .. answer 1 .. answer 2 .. answer 3 <More answers> I am aware of several ways to do this: I could calculate all answers, but show only the first N of them. For certain kinds of calulations, I could use a kind of setoff argument. But I would like to do it in a more general and (hopefully) efficient way: I want the function or object that calculates the answers to be "frozen" at the point at which it has already calculated N answers. If the function gets a <More answers>-signal within a reasonable period of time, it goes on producing more answers exactly at the point at which it got frozen. If no signal is sent, the function call is terminated automatically after M seconds. Note that, although the program to be written is a web application, this is not a question about web application specific things. My only difficulty is how to "freeze" function calls. Has anyone done something of this kind? Santiago
From: Peter Otten on 10 Aug 2010 08:10 Santiago Caracol wrote: > Hello, > > I want to write a web application that does this: > > (1) The user submits a query: > > --------------------------------- > | What is the answer? | > --------------------------------- > <Submit> > > (2) The web server gives the user N answers and a button saying "More > answers": > > . answer 1 > . answer 2 > . answer 3 > > <More answers> > > I am aware of several ways to do this: I could calculate all > answers, but show only the first N of them. For certain kinds of > calulations, > I could use a kind of setoff argument. But I would like to do it in a > more general > and (hopefully) efficient way: > > I want the function or object that calculates the answers to be > "frozen" at the point at which it has already calculated N answers. If > the function gets a <More answers>-signal within a reasonable period > of time, it goes on producing more answers exactly at the point at > which it got frozen. If no signal is sent, the function call is > terminated automatically after > M seconds. > > Note that, although the program to be written is a web application, > this is not a question about web application specific things. My only > difficulty is how to "freeze" function calls. > > Has anyone done something of this kind? Python offers an elegant mechanism to calculate values on demand: the generator function: >>> def calculate_answers(): .... for i in range(100): .... print "calculating answer #%d" % i .... yield i * i .... >>> from itertools import islice >>> gen = calculate_answers() This builds the generator but doesn't run the code inside. Now let's look at the first three "answers": >>> for answer in islice(gen, 3): .... print "the answer is", answer .... calculating answer #0 the answer is 0 calculating answer #1 the answer is 1 calculating answer #2 the answer is 4 If you repeat the last step you get the next three answers: >>> for answer in islice(gen, 3): .... print "the answer is", answer .... calculating answer #3 the answer is 9 calculating answer #4 the answer is 16 calculating answer #5 the answer is 25 Peter
From: Santiago Caracol on 10 Aug 2010 08:30 > Python offers an elegant mechanism to calculate values on demand: the > generator function: > > >>> def calculate_answers(): > > ... for i in range(100): > ... print "calculating answer #%d" % i > ... yield i * i > ... > Thanks for pointing this out. I was aware of the yield statement. My problem is this: (1) The user submits a query: --------------------------------- | What is the answer? | --------------------------------- <Submit> (2) The web server gives the user N answers and a button saying "More answers": .. answer 1 .. answer 2 .. answer 3 <More answers> At this stage the function that writes html to the user has been called. The call must be terminated, or else, the user doesn't get any html. This means that the call of the answer-calculating function, whether it uses yield or not, is also terminated. This means, when the user presses the <More answers>-button, the calculation has to start at the beginning.
From: Peter Otten on 10 Aug 2010 08:48 Santiago Caracol wrote: >> Python offers an elegant mechanism to calculate values on demand: the >> generator function: >> >> >>> def calculate_answers(): >> >> ... for i in range(100): >> ... print "calculating answer #%d" % i >> ... yield i * i >> ... >> > > Thanks for pointing this out. I was aware of the yield statement. > > My problem is this: > > (1) The user submits a query: > > --------------------------------- > | What is the answer? | > --------------------------------- > <Submit> > > (2) The web server gives the user N answers and a button saying "More > answers": > > . answer 1 > . answer 2 > . answer 3 > > <More answers> > > At this stage the function that writes html to the user has been > called. The call must be terminated, or else, the user doesn't get any > html. This means that the call of the answer-calculating function, > whether it uses yield or not, is also terminated. This means, when the > user presses the <More answers>-button, the calculation has to start > at the beginning. Adapted from the wsgiref documentation at http://docs.python.org/library/wsgiref.html $ cat wsgi_demo.py from wsgiref.util import setup_testing_defaults from wsgiref.simple_server import make_server from itertools import count, islice def answers(): for i in count(): yield "Answer #%d\n" % i gen = answers() def simple_app(environ, start_response): setup_testing_defaults(environ) status = '200 OK' headers = [('Content-type', 'text/plain')] start_response(status, headers) return islice(gen, 3) httpd = make_server('', 8000, simple_app) print "Serving on port 8000..." httpd.serve_forever() Run the above with $ python wsgi_demo.py Serving on port 8000... Now point your favourite browser to http://localhost:8000/ and hit refresh. Peter
From: Santiago Caracol on 10 Aug 2010 09:56
> Run the above with > > $ python wsgi_demo.py > Serving on port 8000... > Thanks a lot for this code. The problem with it is that the whole application IS a generator function. That means that if I run the code at, say foo.org, then any user that visits the site will augment the answer number of the server running at foo.org. What I am trying to do is to process specific queries for different users. Each user is supposed to get his very own answers to his very own questions. And if a user doesn't hit the <More answers>-button during a certain period of time, the generator or function call reponsible for answering his question is supposed to be killed or thrown-away or forgotten. If the user asks a new question (while the answers to the old question are still being displayed), then the generator or function call is also supposed to be forgotten and a new generator or function call -- one that matches the user's new question -- is supposed to be initiated. Santiago |