web-dev-qa-db-fra.com

Python Attribuer une valeur à une variable pendant la condition dans la boucle while

Une simple question sur la syntaxe Python. Je veux affecter une valeur d'une fonction à une variable pendant la condition pour une boucle while. Lorsque la valeur renvoyée par la fonction est fausse, la boucle doit se rompre Je sais comment le faire en PHP.

while (($data = fgetcsv($fh, 1000, ",")) !== FALSE) 

Cependant, lorsque j'essaie une syntaxe similaire dans Python j'obtiens une erreur de syntaxe.

20
Borut Flis

Vous ne pouvez pas utiliser d'affectation dans une expression. L'affectation est elle-même une instruction, et vous ne pouvez pas combiner Python.

Il s'agit d'un choix explicite fait par les concepteurs de langage; il est trop facile d'utiliser accidentellement un = et de l'attribuer, là où vous vouliez utiliser deux == et tester l'égalité.

Déplacez l'affectation dans la boucle, ou affectez avant la boucle, et affectez de nouvelles valeurs dans la boucle elle-même.

Pour votre exemple spécifique, le Python csv module vous donne une API de niveau supérieur et vous seriez en boucle sur le csv.reader() au lieu:

with open(csvfilename, 'rb') as csvfh:
    reader = csv.reader(csvfh)
    for row in reader:

J'ai rarement , voire jamais, besoin d'assigner dans une construction en boucle. Il existe généralement une (bien) meilleure façon de résoudre le problème en question.

Cela dit, à partir de Python 3.8 le langage aura en fait des expressions d'affectation, en utilisant := Comme opérateur d'affectation. Voir PEP 572 . Les expressions d'affectation sont en fait utile dans les compréhensions de liste, par exemple, lorsque vous devez à la fois inclure une valeur de retour de méthode dans la liste que vous créez et devez pouvoir utiliser cette valeur dans un test.

Maintenant, vous devez utiliser une expression de générateur:

absolute = (os.path.abspath(p) for p in files)
filtered = [abs for abs in absolute if included(abs)]

mais avec les expressions d'affectation, vous pouvez incorporer l'appel os.path.abspath():

filtered = [abs for p in files if included(abs := os.path.abspath(p))]
28
Martijn Pieters

Vous ne pouvez pas faire cela en Python, aucune affectation dans les expressions. Au moins, cela signifie que vous ne tapez pas accidentellement == au lieu de = ou l'inverse et que cela fonctionne.

Traditionnel Python consiste à utiliser simplement True et à casser:

while True:
    data = fgetcsv(fh, 1000, ",")
    if not data:
        break
    # Use data here

Mais de nos jours, je mettrais cela dans un générateur:

def data_parts(fh):
    while True:
        data = fgetcsv(fh, 1000, ",")
        if not data:
            break
        yield data

de sorte que dans le code qui utilise le fichier, la laideur soit cachée:

for data in data_parts(fh):
    # Use data here

Bien sûr, si c'est réellement la lecture CSV que vous faites, utilisez le module csv.

17
RemcoGerlich

J'ai écrit un petit Python, que j'appelle let , qui vous permet d'effectuer une affectation de variable partout où une fonction est autorisée.

Installez-le comme ceci:

pip install let

Je crois que ce qui suit accomplira ce que vous recherchez:

from let import let

while let(data = fgetcsv(fh, 1000, ',')):
    # Do whatever you'd like with data here

Cependant ... le commentaire de Duncan, la question d'origine disant d'utiliser iter est intéressante. Je n'étais pas au courant de la fonction jusqu'à ce qu'il l'ait évoquée, et je crois maintenant que cela pourrait être une meilleure solution que la mienne. C'est discutable - iter nécessite qu'une sentinelle soit explicitement fournie, tandis que la mienne s'en fiche et attend simplement que fgetcsv retourne toute valeur de Falsey.

4
ArtOfWarfare