2010-02-19 8 views
1

J'ai une autre question Python débutant. J'ai la pièce suivante de code que j'ai un sentiment est pas écrit pythonique comme il devrait être:python basic while loop

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

L'entrée à ce script est une page HTML qui peut avoir un certain nombre de champs d'entrée nommés « myfield # "où # commence à 0 et augmente séquentiellement. En Perl, je ferais quelque chose de plus comme ceci:

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

Mais ce n'est pas une syntaxe valide en Python. Je sais ce que je vais faire, mais y a-t-il un meilleur moyen? Je vous remercie.

Répondre

5

La nature "sans limite" d'un compteur simple a un certain attrait. Cependant, c'est aussi l'occasion pour quelqu'un de tenter une attaque de Déni de Service en usurpant un formulaire avec des milliards de champs. Le simple fait de compter les champs peut bloquer votre serveur Web lorsque vous tentez de traiter ces milliards de champs.

Étant donné que Python se convertit automatiquement en long, le dépassement de 2 milliards habituel ne s'applique pas. Quelqu'un pourrait vraiment punir votre site avec des dizaines de milliards de champs.

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 
+0

Excellente pensée! – Wes

+1

L'usurpation d'un milliard de champs nécessiterait cependant de fournir des gigaoctets d'informations dans la requête. Si le serveur accepte cela, c'est un DOS seul, ne nécessitant aucun code python. – recursive

+0

@recursive. Django évalue la demande POST paresseusement, mais si vous continuez à demander des valeurs, il continuera à accepter les entrées du client. Je suppose que vous pouvez vérifier l'en-tête contenu-longueur pour empêcher ce genre de chose, mais est-ce que tous les navigateurs (et tous les clients) le fournissent? –

1

vous pouvez le faire. Je considère cela plus "flexible" car je peux donner toutes les conditions que je veux, autant que je veux, dans la boucle while. Mais encore une fois, certains diront son goût personnel.

rowindex = 0 
while 1: 
    myid = params.getfirst('myfield'+rowindex) 
    if not myid: #or check for length of 0 , etc, then break 
     break 
    rowindex+=1 
+0

Mon goût personnel dit 'tout true', ese ;-) – gruszczy

+0

sûr. Je viens d'enregistrer 3 caractères, c'est tout :) – ghostdog74

2

Je pense que je ferais un petit générateur pour encapsuler complètement la logique en boucle:

import itertools 

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

afin que l'application (« business ») peut être plus proprement vu dans le flux principal:

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

en particulier si dosomething_with est en ligne. Les générateurs sont vraiment "le pyjama du chat" pour séparer proprement la logique de boucle riche/complexe de la logique applicative/métier.

Si pour une raison particulière, je tenais à les garder fusionnés dans ce cas particulier, je voudrais encore éviter la faible abstraction rowindex = 0/while/code rowindex += 1 en faveur de for rowindex in itertools.count(): que je pense est plus claire et plus nette, ainsi que plus concis. Ce cadrage global permet également de basculer entre la limitation de la boucle, comme dans la réponse acceptée, si et quand vous décidez de le faire, et d'avoir une boucle non bornée, comme dans la question originale - il suffit de changer itertools.count() à/de xrange(N).

-1

Essayez de faire cette

While 1: 

    codehere