Question

Parfois, je casse de longues conditions dans si est réparti sur plusieurs lignes. La manière la plus évidente de le faire est:

  if (cond1 == 'val1' and cond2 == 'val2' and
      cond3 == 'val3' and cond4 == 'val4'):
      do_something

n’est pas très attrayant visuellement, car l’action se confond avec les conditions. Cependant, c’est la méthode la plus naturelle en utilisant l’indentation correcte de 4 espaces en Python.

Pour le moment, j'utilise:

  if (    cond1 == 'val1' and cond2 == 'val2' and
          cond3 == 'val3' and cond4 == 'val4'):
      do_something

Mais ce n’est pas très joli. : -)

Pouvez-vous recommander un autre moyen?

Était-ce utile?

La solution

Vous n'avez pas besoin d'utiliser 4 espaces sur votre deuxième ligne conditionnelle. Peut-être utiliser:

if (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something

N'oubliez pas non plus que l'espace est plus flexible que vous ne le pensez:

if (   
       cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something
if    (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something

Ces deux-là sont assez laids, cependant.

Peut-être perdre les crochets (le Guide de la rédaction décourage cela cependant)?

if cond1 == 'val1' and cond2 == 'val2' and \
   cond3 == 'val3' and cond4 == 'val4':
    do_something

Cela vous donne au moins une certaine différenciation.

Ou même:

if cond1 == 'val1' and cond2 == 'val2' and \
                       cond3 == 'val3' and \
                       cond4 == 'val4':
    do_something

Je pense que je préfère:

if cond1 == 'val1' and \
   cond2 == 'val2' and \
   cond3 == 'val3' and \
   cond4 == 'val4':
    do_something

Voici le Guide de style , qui ( depuis 2010) recommande l'utilisation de crochets.

Autres conseils

J'ai eu recours à ce qui suit dans le cas dégénéré où il s'agit simplement d'ET ou d'OR.

if all( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

if any( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

Il rase quelques caractères et indique clairement qu'il n'y a pas de subtilité dans la condition.

Quelqu'un doit défendre l'utilisation des espaces verticaux ici! :)

if (     cond1 == val1
     and cond2 == val2
     and cond3 == val3
   ):
    do_stuff()

Cela rend chaque condition clairement visible. Il permet également une expression plus propre de conditions plus complexes:

if (    cond1 == val1
     or 
        (     cond2_1 == val2_1
          and cond2_2 >= val2_2
          and cond2_3 != bad2_3
        )
   ):
    do_more_stuff()

Oui, nous échangeons un peu d’immobilier vertical pour plus de clarté. Ça vaut vraiment le coup, IMO.

Voici ce que je pense très personnellement: les conditions longues sont (à mon avis) une odeur de code qui suggère de refactoriser une fonction / méthode de retour booléen. Par exemple:

def is_action__required(...):
    return (cond1 == 'val1' and cond2 == 'val2'
            and cond3 == 'val3' and cond4 == 'val4')

Maintenant, si je trouvais le moyen de donner un bon rendu aux conditions multilignes, je me contenterais probablement de les avoir et d'éviter le refactoring.

D'autre part, les perturber mon sens esthétique incite au refactoring.

Ma conclusion est donc que les conditions de ligne multiples devraient sembler laides et que cela les incite à les éviter.

Cela ne s’améliore pas tellement, mais ...

allCondsAreOK = (cond1 == 'val1' and cond2 == 'val2' and
                 cond3 == 'val3' and cond4 == 'val4')

if allCondsAreOK:
   do_something

Je préfère ce style lorsque j'ai une condition si importante:

if (
    expr1
    and (expr2 or expr3)
    and hasattr(thingy1, '__eq__')
    or status=="HappyTimes"
):
    do_stuff()
else:
    do_other_stuff()

Je suggère de déplacer les mots clés et vers la deuxième ligne et d'indenter toutes les lignes contenant des conditions avec deux espaces au lieu de quatre:

if (cond1 == 'val1' and cond2 == 'val2'
  and cond3 == 'val3' and cond4 == 'val4'):
    do_something

C’est exactement comment je résous ce problème dans mon code. Avoir un mot-clé comme premier mot de la ligne rend la condition beaucoup plus lisible et réduire le nombre d'espaces différencie davantage la condition de l'action.

Il semble intéressant de citer PEP 0008 (guide de style officiel de Python), car il commente cette question avec une longueur modeste:

  

Lorsque la partie conditionnelle d'une instruction si est suffisamment longue pour nécessiter son écriture sur plusieurs lignes, il convient de noter que la combinaison d'un mot clé à deux caractères (c'est-à-dire si ), plus un espace unique, plus une parenthèse ouvrante crée un retrait naturel de 4 espaces pour les lignes suivantes du conditionnel multiligne. Cela peut produire un conflit visuel avec la suite de code indentée imbriquée dans l'instruction if , qui serait également naturellement indentée de 4 espaces. Ce PEP ne prend pas de position explicite sur la manière (ou non) de distinguer visuellement davantage ces lignes conditionnelles de la suite imbriquée à l'intérieur de l'instruction if . Les options acceptables dans cette situation incluent, mais ne sont pas limitées à:

# No extra indentation.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

Notez que " n'est pas limité à " dans la citation ci-dessus; En plus des approches suggérées dans le guide de style, certaines de celles suggérées dans d'autres réponses à cette question sont également acceptables.

Voici ce que je fais, rappelez-vous que "Tous". et " any " accepte un itératif, alors je viens de mettre une longue condition dans une liste et laisser "tout" faire le travail.

condition = [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4']

if all(condition):
   do_something

Je suis surpris de ne pas voir ma solution préférée,

if (cond1 == 'val1' and cond2 == 'val2'
    and cond3 == 'val3' and cond4 == 'val4'):
    do_something

Puisque et sont des mots clés, ils sont mis en évidence par mon éditeur et ont un aspect suffisamment différent du do_something situé en dessous.

Personnellement, j'aime ajouter du sens à de longues déclarations if. Il faudrait que je cherche dans le code pour trouver un exemple approprié, mais voici le premier exemple qui me vient à l’esprit: disons que j’ai un problème avec une logique bizarre où je veux afficher une certaine page en fonction de nombreuses variables.

Anglais: "Si l'utilisateur connecté n'est PAS un enseignant administrateur, mais uniquement un enseignant régulier et qu'il n'est pas un étudiant lui-même ..."

if not user.isAdmin() and user.isTeacher() and not user.isStudent():
    doSomething()

Bien sûr, cela peut sembler correct, mais la lecture de ces déclarations si représente beaucoup de travail. Pourquoi ne pas assigner la logique à une étiquette qui a du sens. Le " label " est en fait le nom de la variable:

displayTeacherPanel = not user.isAdmin() and user.isTeacher() and not user.isStudent()
if displayTeacherPanel:
    showTeacherPanel()

Cela peut sembler idiot, mais vous pouvez également avoir une autre condition dans laquelle vous voulez UNIQUEMENT afficher un autre élément si, et seulement si, vous affichez le panneau de l'enseignant OU si l'utilisateur a accès à cet autre panneau spécifique par défaut:

if displayTeacherPanel or user.canSeeSpecialPanel():
    showSpecialPanel()

Essayez d’écrire la condition ci-dessus sans utiliser de variables pour stocker et étiqueter votre logique. Vous obtenez non seulement une instruction logique très confuse et difficile à lire, mais vous vous répétez tout simplement. S’il existe des exceptions raisonnables, rappelez-vous: ne vous répétez pas (DRY).

"Tous" et " any " sont sympas pour les nombreuses conditions du même type. MAIS ils évaluent toujours toutes les conditions. Comme indiqué dans cet exemple:

def c1():
    print " Executed c1"
    return False
def c2():
    print " Executed c2"
    return False


print "simple and (aborts early!)"
if c1() and c2():
    pass

print

print "all (executes all :( )"
if all((c1(),c2())):
    pass

print

(J'ai légèrement modifié les identifiants, car les noms à largeur fixe ne sont pas représentatifs du code réel. Du moins, ce n'est pas du code réel que je rencontre et cela va démentir la lisibilité d'un exemple.)

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4"):
    do_something

Cela fonctionne bien pour " et " et " & " (il est important qu’ils soient les premiers sur la deuxième ligne), mais beaucoup moins pour les autres conditions longues. Heureusement, les premiers semblent être le cas le plus courant alors que les derniers sont souvent facilement réécrites avec une variable temporaire. (Ce n’est généralement pas difficile, mais il peut être difficile ou beaucoup moins évident / lisible de conserver le court-circuitage de "et" / "ou" lors de la réécriture.)

Depuis que j'ai trouvé cette question de votre article de blog sur C ++ , j'inclue que mon style C ++ est identique:

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4") {
    do_something
}

Ajout à ce que @krawyoti a dit ... Les longues conditions sentent mauvais, car elles sont difficiles à lire et à comprendre. L'utilisation d'une fonction ou d'une variable rend le code plus clair. En Python, je préfère utiliser l’espace vertical, mettre entre parenthèses et placer les opérateurs logiques au début de chaque ligne pour que les expressions ne ressemblent pas à "flottantes".

conditions_met = (
    cond1 == 'val1' 
    and cond2 == 'val2' 
    and cond3 == 'val3' 
    and cond4 == 'val4'
    )
if conditions_met:
    do_something

Si les conditions doivent être évaluées plusieurs fois, comme dans une boucle while , il est préférable d'utiliser une fonction locale.

Clair et simple, passe également les contrôles pep8:

if (
    cond1 and
    cond2
):
    print("Hello World!")

Ces derniers temps, je préférais les fonctions all et any , étant donné que je mélange rarement les comparaisons And et Or, cela fonctionne bien et présente l'avantage supplémentaire de Failing Early. avec compréhension des générateurs:

if all([
    cond1,
    cond2,
]):
    print("Hello World!")

N'oubliez pas de passer dans un seul itératif! Passer en N-arguments n’est pas correct.

Remarque: tout correspond à de nombreuses comparaisons ou , tout correspond à de nombreuses comparaisons et .

Ceci se combine bien avec les compréhensions de générateur, par exemple:

# Check if every string in a list contains a substring:
my_list = [
    'a substring is like a string', 
    'another substring'
]

if all('substring' in item for item in my_list):
   print("Hello World!")

# or

if all(
    'substring' in item
    for item in my_list
):
    print("Hello World!")

Pour en savoir plus sur: compréhension du générateur

Que se passe-t-il si nous insérons seulement une ligne vierge supplémentaire entre la condition et le corps et faisons le reste de manière canonique?

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'):

    do_something

p.s. J'utilise toujours des tabulations, pas des espaces; Je ne peux pas peaufiner ...

Juste quelques autres idées aléatoires pour des raisons de complétude. S'ils travaillent pour vous, utilisez-les. Sinon, vous feriez probablement mieux d'essayer autre chose.

Vous pouvez également le faire avec un dictionnaire:

>>> x = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> y = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> x == y
True

Cette option est plus compliquée, mais vous pouvez également la trouver utile:

class Klass(object):
    def __init__(self, some_vars):
        #initialize conditions here
    def __nonzero__(self):
        return (self.cond1 == 'val1' and self.cond2 == 'val2' and
                self.cond3 == 'val3' and self.cond4 == 'val4')

foo = Klass()
if foo:
    print "foo is true!"
else:
    print "foo is false!"

Ne savez pas si cela fonctionne pour vous, mais c'est une autre option à considérer. Voici un autre moyen:

class Klass(object):
    def __init__(self):
        #initialize conditions here
    def __eq__(self):
        return (self.cond1 == 'val1' and self.cond2 == 'val2' and
               self.cond3 == 'val3' and self.cond4 == 'val4')

x = Klass(some_values)
y = Klass(some_other_values)
if x == y:
    print 'x == y'
else:
    print 'x!=y'

Les deux derniers que je n'ai pas encore testés, mais les concepts devraient suffire à vous lancer, si c'est ce que vous voulez faire.

(Et pour mémoire, s'il ne s'agit que d'une fois, vous feriez probablement mieux d'utiliser la méthode que vous avez présentée au début. Si vous faites la comparaison dans de nombreux endroits, ces méthodes peuvent améliorer la lisibilité. assez pour que vous ne vous sentiez pas si mal à propos du fait qu’ils soient un peu hacky.)

Ce que je fais habituellement est:

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something

De cette manière, le corset et le colon marquent visuellement la fin de notre condition.

J'ai eu du mal à trouver un moyen décent de faire cela aussi, alors je viens de proposer une idée (pas une solution miracle, car il s'agit principalement d'une question de goût).

if bool(condition1 and
        condition2 and
        ...
        conditionN):
    foo()
    bar()

Je trouve quelques avantages dans cette solution par rapport aux autres que j'ai vus, à savoir, vous obtenez exactement 4 espaces d'indentation (bool) supplémentaires, permettant à toutes les conditions de s'aligner verticalement, et le corps de l'instruction if peut être mis en retrait de manière claire (ish). Cela conserve également les avantages de l'évaluation des courts-circuits des opérateurs booléens, mais ajoute évidemment la surcharge d'un appel de fonction qui ne fait fondamentalement rien. Vous pouvez argumenter (valablement) que toute fonction renvoyant son argument pourrait être utilisée ici au lieu de bool, mais comme je l'ai dit, c'est juste une idée et c'est finalement une question de goût.

Assez drôle, alors que j’écrivais ceci et pensais au "problème", j’ai eu une nouvelle idée , , qui supprime la surcharge d’un appel de fonction. Pourquoi ne pas indiquer que nous sommes sur le point d'entrer dans une condition complexe en utilisant des paires de parenthèses supplémentaires? Disons 2 de plus, pour donner un joli 2 espace des sous-conditions relatives au corps de l'instruction if. Exemple:

if (((foo and
      bar and
      frob and
      ninja_bear))):
    do_stuff()

Je suis un peu comme ça parce que quand vous la regardez, une cloche sonne immédiatement dans votre tête et vous dit "hé, il y a une chose complexe qui se passe ici!" . Oui, je sais que les parenthèses ne facilitent pas la lisibilité, mais ces conditions devraient apparaître assez rarement, et quand elles se présenteront, vous devrez vous arrêter et les lire attentivement quand même (car elles sont complexes ).

Quoi qu'il en soit, juste deux autres propositions que je n'ai pas vues ici. J'espère que cela aide quelqu'un:)

Vous pouvez le scinder en deux lignes

total = cond1 == 'val' and cond2 == 'val2' and cond3 == 'val3' and cond4 == val4
if total:
    do_something()

Ou même ajouter une condition à la fois. De cette façon, au moins il sépare le fouillis de si .

Je sais que ce fil est ancien, mais j'ai du code Python 2.7 et PyCharm (4.5) se plaint toujours de ce cas:

if foo is not None:
    if (cond1 == 'val1' and cond2 == 'val2' and
        cond3 == 'val3' and cond4 == 'val4'):
            # some comment about do_something
            do_something

Même avec l'avertissement PEP8 "ligne visuellement indentée avec le même retrait que la ligne logique suivante", le code actuel est-il complètement correct? Ce n'est pas "trop ??indenté?"

... il y a des moments où j'aurais aimé que Python morde la balle et partit avec des accolades. Je me demande combien de bugs ont été introduits accidentellement au fil des ans en raison d'une erreur d'indentation accidentelle ...

Tous les répondants qui fournissent également plusieurs conditions pour la déclaration if sont aussi moche que le problème présenté. Vous ne résolvez pas ce problème en faisant la même chose.

Même la réponse PEP 0008 est répugnante.

Voici une approche beaucoup plus lisible

condition = random.randint(0, 100) # to demonstrate
anti_conditions = [42, 67, 12]
if condition not in anti_conditions:
    pass

Voulez-vous que je mange mes mots? Convainquez-moi que vous avez besoin de plusieurs conditions et je vais littéralement l’imprimer et la manger pour vous distraire.

Je pense que la solution de @ zkanda serait bien avec une torsion mineure. Si vos conditions et vos valeurs figurent dans leurs listes respectives, vous pouvez utiliser une compréhension de liste pour faire la comparaison, ce qui rendrait les choses plus générales en ajoutant des paires condition / valeur.

conditions = [1, 2, 3, 4]
values = [1, 2, 3, 4]
if all([c==v for c, v in zip(conditions, values)]):
    # do something

Si je voulais coder en dur une déclaration comme celle-ci, je l'écrirais ainsi pour des raisons de lisibilité:

if (condition1==value1) and (condition2==value2) and \
   (condition3==value3) and (condition4==value4):

Et juste pour lancer une autre solution avec un iand opérateur :

proceed = True
for c, v in zip(conditions, values):
    proceed &= c==v

if proceed:
    # do something

Mettez vos conditions dans une liste, puis faites-le. comme:

if False not in Conditions:
    do_something

Je constate que lorsque j'ai de longues conditions, j'ai souvent un corps avec code court. Dans ce cas, je double-indenter le corps, par exemple:

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'):
        do_something
  if cond1 == 'val1' and \
     cond2 == 'val2' and \
     cond3 == 'val3' and \
     cond4 == 'val4':
      do_something

ou si cela est plus clair:

  if cond1 == 'val1'\
     and cond2 == 'val2'\
     and cond3 == 'val3'\
     and cond4 == 'val4':
      do_something

Il n'y a pas de raison que le retrait soit un multiple de 4 dans ce cas, par exemple. voir "Aligné sur le séparateur d'ouverture":

http: //google-styleguide.googlecode. com / svn / trunk / pyguide.html? showone = Indentation # Indentation

Voici une autre approche:

cond_list = ['cond1 == "val1"','cond2=="val2"','cond3=="val3"','cond4=="val4"']
if all([eval(i) for i in cond_list]):
 do something

Cela facilite également l'ajout d'une autre condition sans modifier l'instruction if en ajoutant simplement une autre condition à la liste:

cond_list.append('cond5=="val5"')

J'utilise habituellement:

if ((cond1 == 'val1' and cond2 == 'val2' and
     cond3 == 'val3' and cond4 == 'val4')):
    do_something()

if our if & amp; une condition else doit exécuter plusieurs instructions à l'intérieur de celle-ci que nous pouvons écrire comme ci-dessous. Chaque fois que nous avons si autre exemple avec une déclaration à l'intérieur.

Merci, ça marche pour moi.

#!/usr/bin/python
import sys
numberOfArgument =len(sys.argv)
weblogic_username =''
weblogic_password = ''
weblogic_admin_server_host =''
weblogic_admin_server_port =''


if numberOfArgument == 5:
        weblogic_username = sys.argv[1]
        weblogic_password = sys.argv[2]
        weblogic_admin_server_host =sys.argv[3]
        weblogic_admin_server_port=sys.argv[4]
elif numberOfArgument <5:
        print " weblogic UserName, weblogic Password and weblogic host details are Mandatory like, defalutUser, passwordForDefaultUser, t3s://server.domainname:7001 ."
        weblogic_username = raw_input("Enter Weblogic user Name")
        weblogic_password = raw_input('Enter Weblogic user Password')
        weblogic_admin_server_host = raw_input('Enter Weblogic admin host ')
        weblogic_admin_server_port = raw_input('Enter Weblogic admin port')
#enfelif
#endIf
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top