views:

156

answers:

4

I have another newbie Python question. I have the following piece of code that I have a feeling is not written as pythonic as it should be:

    rowindex = 0
    while params.getfirst('myfield'+rowindex):
        myid = params.getfirst('myfield'+rowindex)
        # do stuff with myid
        rowindex+=1

The input to this script is an HTML page that can have any number of input fields named "myfield#" where # starts at 0 and increases sequentially. In Perl, I would do something more like this:

    rowindex = 0
    while myid =  params.getfirst('myfield'+rowindex):
        #do stuff with myid
        rowindex+=1

But that is not valid syntax in Python. I know what I have will work, but is there a better way? Thank you.

+1  A: 

you can do this. I consider this more "flexible" as I can give any conditions i want, as many as i want, inside the while loop. But then again, some will say its personal taste.

rowindex = 0
while 1:
    myid = params.getfirst('myfield'+rowindex)
    if not myid:  #or check for length of 0 , etc, then break
       break
    rowindex+=1
ghostdog74
My personal taste says `while True`, ese ;-)
gruszczy
sure. I just save 3 characters, that's all :)
ghostdog74
+6  A: 

The "unbounded" nature of a simple counter has some appeal. However, it's also an opportunity for someone to attempt a Denial of Service attack by spoofing a form with billions of fields. Simply counting through the fields could stall your web server as you attempt to process those billions of fields.

Since Python converts to long automatically, the usual 2 billion integer overflow doesn't apply. Someone could really punish your site with 10's of billions of fields.

for i in range(1024): # some sensible upper limit, beyond which the input is suspicious
    myid= params.getfirst("myfield%d" % i)
    if not myid: break
        # do stuff with myid
S.Lott
Excellent thought!
Wes
Spoofing a billion fields would require provide gigabytes of information in the request though. If the server accepts that, that's a DOS on its own, not requiring any python code.
recursive
@recursive. Django evaluates the POST request lazily, but if you keep asking for values, it will keep accepting input from the client. I suppose you could check the content-length header to prevent this kind of thing, but do all browsers (and all clients) provide it?
S.Lott
+2  A: 

I think I'd make a little generator to fully encapsulate the looping logic:

import itertools

def genit(params):
  for rowindex in itertools.count():
    theid = params.getfirst('myfield%s' % rowindex)
    if not theid: break
    yield theid

so that application ("business") logic can be more cleanly seen in the main flow:

for myid in genit(params):
    dosomething_with(myid)

especially if dosomething_with is inline. Generators are really "the cat's pajamas" to cleanly separate rich / complex looping logic from application / business logic.

If for some special reason I was keen to keep them merged in this particular case, I still would avoid the low-abstraction rowindex = 0 / while / rowindex += 1 code in favor of for rowindex in itertools.count(): which I think is clearer and sharper as well as more concise. This overall framing also makes it easier to switch between limiting the loop, as in the accepted answer, if and when you decide to do that, and having an unbounded loop, as in the original question -- just change itertools.count() to/from xrange(N).

Alex Martelli
A: 

Try Doing this

While 1:

    codehere
sourD