Style des conditions multilignes dans les instructions «si»? [fermé]


677

Parfois, je casse de longues conditions ifsur plusieurs lignes. La façon 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 très attrayant visuellement, car l'action se confond avec les conditions. Cependant, c'est la manière naturelle d'utiliser l'indentation Python correcte de 4 espaces.

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 une autre façon?


2
Si votre éditeur utilise le package pep8 Python pour détecter quand avertir des violations PEP8 , vous devrez soit désactiver l'erreur E125, soit trouver une solution de formatage qui réponde aux pep8critères du package. Le pep8du paquet de # 126 question est de fixer le paquet à suivre strictement les spécifications de pep8. La discussion sur le problème comprend quelques suggestions de style également vues ici.
akaihola

1
Notez que pour le premier exemple, pep8 lancera "E129 ligne visuellement indentée avec le même retrait que la ligne logique suivante".
Taylor Edmiston

Cette question est très ancienne et a une tonne d'opinions, mais elle est sans équivoque basée sur l'opinion. Le langage «n'est pas très attrayant» et «n'est pas très joli» énonce les critères selon lesquels la réponse supposément correcte est celle qui correspond le mieux à la préférence esthétique du demandeur (c.-à-d. Une opinion). Je pourrais poser exactement la même question et prétendre qu'il ne s'agit pas d'un doublon car mon goût esthétique le qualifie de différent et conduira à une "bonne" réponse différente.
Z4-tier

@ Z4-tier: oui, c'est basé sur l'opinion. Mais cela a été demandé il y a 12 ans. SO était un endroit différent et plus gentil à l'époque. Récemment, il a accumulé des downvotes depuis que les normes de SO ont changé. Pourtant, après avoir été vu> 1 million de fois, j'espère que cela fait plus de bien que de mal dans le monde. Je peux certainement voir des gens s'interroger sur la même question aujourd'hui, googler, atterrir sur cette discussion et trouver utile d'étalonner leur pensée. Il existe plusieurs réponses très votées parmi lesquelles choisir.
Eli Bendersky

@EliBendersky est entièrement d'accord. C'est comme si SO a une crise d'identité en cours: s'il ne correspond manifestement pas aux «règles» (le nombre de réponses valides en témoigne), il est tout aussi clair qu'il ajoute de la valeur. Toutes choses étant égales par ailleurs, je préfère travailler avec quelqu'un qui a développé des vues articulables et raisonnées sur le style de codage, même si leurs vues diffèrent des miennes.
Niveau Z4

Réponses:


750

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

Les deux sont assez laids cependant.

Peut-être perdre les crochets (le Guide de style 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 Style Guide , qui (depuis 2010) recommande d'utiliser des crochets.


45
Notez que les solutions de fin \ ne sont pas recommandées par PEP 8. Une raison est que si un espace est ajouté par erreur après un \ il peut ne pas s'afficher dans votre éditeur et le code devient syntaxiquement incorrect.
Eric O Lebigot

14
C'est faux, le guide de style dit "Les longues lignes peuvent être coupées sur plusieurs lignes en enveloppant les expressions entre parenthèses. Elles doivent être utilisées de préférence à l'utilisation d'une barre oblique inverse pour la continuation de la ligne." Vous pouvez le voir ici: python.org/dev/peps/pep-0008/#maximum-line-length
joshcartme

8
@joshcartme Le PEP a changé à hg.python.org/peps/rev/7a48207aaab6 pour décourager explicitement les contre-obliques. Je mettrai à jour la réponse.
Harley Holcombe

3
Merci, c'est probablement une bonne idée de mettre à jour vos exemples car ils ne sont plus recommandés. J'essayais de comprendre cela moi-même et j'étais confus par la différence entre votre réponse et le guide de style (d'où mon commentaire). Je n'essayais pas seulement d'être pédant.
joshcartme

3
PEP 8 décourage désormais la rupture après le andet ifaussi.
virtualxtc

124

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

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 montre clairement qu'il n'y a aucune subtilité à la condition.


4
Il s'agit d'une approche intéressante. Ne résout pas le problème des longues conditions
Eli Bendersky

20
Ce n'est pas grave si vous ne vous souciez pas des courts-circuits.
Constantin

63
le court-circuitage n'est pas toujours rapide. Sans bonnes pratiques de codage, vous pouvez avoir le code existant comme celui - ci: if destroy_world and DestroyTheWorld() == world_is_destroyed: .... Génial, maintenant vous venez de détruire le monde par accident. COMMENT PEUX-TU?
Aaron

4
Je suis surpris que cela ait autant de votes positifs. Cette réponse ignore complètement la question d'origine sur le style des conditionnelles multilignes .
Przemek D

2
Cette expression n'est pas paresseuse. Ce n'est donc pas équivalent si une condition de gardiennage est suivie d'une défaillance éventuelle.
eugene-bright

57

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 nette des 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 le coup IMO.


19
Cela ne semble ni beau ni compatible avec PEP8. PEP8 dit que l'endroit préféré pour contourner un opérateur binaire (par exemple andaussi bien que or) est après l'opérateur, pas avant lui.
Chris Medrela

7
@ChristopherMedrela explique-t-il la raison derrière cela? je pense que placer un saut de ligne avant l'opérateur logique est beaucoup plus clair
Norill Tempest

4
La priorité de l'opérateur est assez courante dans le monde des nœuds. La raison est que nous remarquons et lisons des choses à gauche beaucoup plus rapidement que des choses à droite - au moins dans les cultures occidentales. Très valide en JavaScript, où une virgule oubliée peut provoquer des erreurs silencieuses.
tomekwi

11
Ne faites pas ça s'il vous plait. Non seulement ce n'est pas le cas, PEP8mais il est plus difficile de déterminer l'opération logique avec laquelle vous enchaînez. Je voudrais échouer si cela venait à mon bureau via la révision du code.
Urda

11
À partir de la version actuelle de PEP8, la coupure avant ou après un opérateur binaire est considérée comme acceptable , et avant que l'opérateur soit considéré comme meilleur pour le nouveau code.
Soren Bjornstad

31

Je préfère ce style quand j'ai une condition if terriblement grande:

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

2
+1 pour conserver les retraits où vous pouvez les suivre. J'aime le python et je l'utilise beaucoup, mais je suis constamment ennuyé d'être obligé de mettre en retrait. Le multi-lignes détruit vraiment l'esthétique, même lorsqu'il est bien fait.
mightypile

4
Notez que le fait d'avoir vos opérateurs andet orau début de la ligne viole le PEP 0008 , qui stipule que "l'endroit préféré pour contourner un opérateur binaire est après l'opérateur, pas avant lui". . J'aime avoir le crochet de fermeture et les deux points sur leur propre ligne pour séparer la condition if du corps, (et il est parfaitement possible de le faire tout en gardant vos opérateurs booléens à la fin de la ligne pour la conformité PEP-0008).
Mark Amery

8
à partir de 2016: For decades the recommended style was to break after binary operators. But this can hurt readability in two ways... In Python code, it is permissible to break before or after a binary operator, as long as the convention is consistent locally. For new code Knuth's style is suggested.(le style de Knuth est de commencer la ligne avec l'opérateur).
cowbert

27

Voici mon point de vue très personnel: les conditions longues sont (à mon avis) une odeur de code qui suggère une refactorisation en une fonction / méthode à 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 un moyen de rendre les conditions multilignes plus belles, je me contenterais probablement de les avoir et de sauter le refactoring.

En revanche, les faire perturber mon sens esthétique incite à la refactorisation.

Ma conclusion, par conséquent, est que les conditions de plusieurs lignes doivent sembler moches et c'est une incitation à les éviter.


23

Cela ne s'améliore pas tellement mais ...

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

if allCondsAreOK:
   do_something

1
Alternative intéressante. Mais 2 lignes supplémentaires :-)
Eli Bendersky

Ne fonctionnerait pas vraiment aussi bien dans une boucle itérative, ne fonctionnerait pas avec des fonctions faisant quelque chose ... et pour être juste - moche
Mez

9
brian, je suis en désaccord en partie. L'utilisation de variables pour les résultats intermédiaires d'un calcul peut rendre le code plus facile à comprendre et, dans un langage compilé, n'aura aucun impact sur les performances. Cela ferait probablement l'affaire en python, bien que je n'utiliserais pas du tout python si la performance était si importante.
Mark Baker,

1
@MarkBaker J'étais d'accord avec ce que vous avez écrit, jusqu'à ce que je lise Martin Fowlers "Refactoring". Il fournit un excellent argument selon lequel de telles variables intermédiaires causent plus de tort que d'avantages. Ils inhibent le refactoring ultérieur. Se passer d'eux conduit à un style de programmation plus fonctionnel, qui se prête bien au refactoring. Cela m'a surpris, mais je pense qu'il a raison et s'est efforcé depuis d'éliminer les intermédiaires inutiles comme celui-ci de mon code - même s'ils sont utilisés plusieurs fois.
Jonathan Hartley

2
Bien, mais pourquoi camelCase?! :)
Leonid Shvechikov

19

Je suggère de déplacer le andmot - clé vers la deuxième ligne et de mettre en retrait 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 ainsi que je résous ce problème dans mon code. Le fait d'avoir un mot-clé comme premier mot de la ligne rend la condition beaucoup plus lisible et la réduction du nombre d'espaces distingue encore la condition de l'action.


9
J'ai lu quelque part dans Gries ou Djikstra que mettre l'opérateur logique au début de la ligne - le rendant plus visible - a aidé. Et je fais ça depuis les années 90. Et ça aide.
S.Lott

7
Notez que le Guide de style recommande de mettre le conditionnel à la fin de la ligne.
Harley Holcombe

3
C'est vrai, bien que je ne sois jamais d'accord avec cela. Ce n'est qu'un guide, après tout.
DzinX

8
PEP8 ne recommande plus de mettre le conditionnel en fin de ligne.
Soren Bjornstad

14

Il semble intéressant de citer PEP 0008 (le guide de style officiel de Python), car il commente ce problème de manière modeste:

Lorsque la partie conditionnelle d'une ifdéclaration est suffisamment longue pour exiger qu'elle soit écrite sur plusieurs lignes, il convient de noter que la combinaison d'un mot clé à deux caractères (c'est-à-dire if), plus un seul espace, plus une parenthèse ouvrante crée un 4- naturel retrait d'espace pour les lignes suivantes du conditionnel multiligne. Cela peut produire un conflit visuel avec la suite de code en retrait imbriquée à l'intérieur de la ifdéclaration, qui serait également naturellement en retrait sur 4 espaces. Ce PEP ne prend pas de position explicite sur la manière (ou l'opportunité) de distinguer visuellement ces lignes conditionnelles de la suite imbriquée à l'intérieur de la ifdéclaration. Les options acceptables dans cette situation incluent, sans s'y limiter:

# 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 le "non limité à" dans la citation ci-dessus; outre les 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.


+1 pour PEP8. Cela devrait être accepté, car il s'agit (pratiquement) du guide de style Python officiel.
Michael - Où est Clay Shirky

2
Il convient également de souligner que PEP8 indique explicitement sa position car ce PEP ne prend aucune position explicite sur la façon (ou si) de distinguer visuellement 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 à: ... (coupé) Alors, arrêtez de discuter, allez avec quelque chose que vous aimez!
RayLuo

7

Voici ce que je fais, rappelez-vous que "tous" et "tous" accepte un itérable, donc je mets simplement une condition longue dans une liste et laisse "tous" faire le travail.

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

if all(condition):
   do_something

4

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

Étant donné qu'il ands'agit d'un mot clé, il est mis en surbrillance par mon éditeur et semble suffisamment différent du do_something en dessous.


Mais la ligne de continuation ne se distingue toujours pas de la ligne logique suivante ...
Chris Medrela

1
Notez qu'il s'agit d'une violation PEP 0008 ( "L'endroit préféré pour contourner un opérateur binaire est après l'opérateur, pas avant lui" ). Bien sûr, cela dépend de vous.
Mark Amery

1
Soit dit en passant, ce n'est plus ma solution préférée. ;)
Marius Gedminas

4

Pour ajouter à ce que @krawyoti a dit ... Les longues conditions sentent parce qu'elles sont difficiles à lire et difficiles à 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, entourer les parenthèses et placer les opérateurs logiques au début de chaque ligne afin 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 whileboucle, il est préférable d'utiliser une fonction locale.


1
En plus de cela, vous pouvez déclarer une fonction ou un lambda pour retourner votre vrai faux au lieu de créer une variable supplémentaire.
Techdragon

@Techdragon si les conditions doivent être ailleurs, alors les placer dans un bloc lambda nécessiterait que le bloc lambda soit nommé afin qu'il puisse être référencé plus tard dans la condition if. Si un lambda va être nommé, pourquoi et non une fonction régulière après tout? J'aime personnellement cette expression booléenne réduite.
Sri Kadimisetty

Je suis d'accord, c'est pourquoi j'utiliserais normalement une fonction dans la plupart des cas pour une meilleure lisibilité et une facilité de digestion mentale lors du survol pour comprendre le flux de contrôle du programme. Je mentionne le lambda pour garantir que l'option «plus petite» est également présente au cas où les gens seraient particulièrement soucieux de l'espace.
Techdragon

4

Personnellement, j'aime ajouter du sens aux longues instructions if. Je devrais rechercher dans le code pour trouver un exemple approprié, mais voici le premier exemple qui me vient à l'esprit: disons que je rencontre une logique excentrique où je veux afficher une certaine page en fonction de nombreuses variables.

Anglais: "Si l'utilisateur connecté n'est PAS un enseignant administrateur, mais est juste un enseignant régulier, et n'est pas un élève lui-même ..."

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

Bien sûr, cela peut sembler correct, mais lire ces déclarations if représente beaucoup de travail. Que diriez-vous d'attribuer 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 avoir une autre condition dans laquelle vous souhaitez afficher UNIQUEMENT 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, et non seulement vous vous retrouvez avec une déclaration logique très compliquée et difficile à lire, mais vous venez également de vous répéter. Bien qu'il existe des exceptions raisonnables, n'oubliez pas: ne vous répétez pas (SEC).


3

"all" et "any" sont agréables pour les nombreuses conditions du même type de cas. MAIS ils évaluent toujours toutes les conditions. Comme le montre 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

5
Incorrect! Ils ne le font que parce que vous le faites. Essayez tout (f () pour f dans [c1, c2]).
habnabit

2
Je pense qu'il n'utilisait les fonctions qu'à titre d'exemple, car il peut facilement les faire imprimer quelque chose. Si nous considérons une série d'expressions arbitraires fournies dans une liste à ce moment- all()là, à moins que vous ne les enveloppiez chacune dans un lambda et que vous n'utilisiez votre f()astuce, elles vont toutes être évaluées. En d'autres termes, Aaron: Je pense qu'Anders essayait de parler des conditions en général, en utilisant des callables comme exemple spécifique; mais votre réplique ne s'applique qu'aux fonctions.
Brandon Rhodes

3

(J'ai légèrement modifié les identifiants car les noms à largeur fixe ne sont pas représentatifs du vrai code - du moins pas du vrai code que je rencontre - et démentiront 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 "ou" (il est important qu'ils soient premiers sur la deuxième ligne), mais beaucoup moins pour les autres conditions longues. Heureusement, les premiers semblent être le cas le plus courant tandis que les seconds sont souvent facilement réécrits 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 dans votre article de blog sur C ++ , je vais inclure que mon style C ++ est identique:

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

3

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

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

Ces derniers temps, j'ai préféré les fonctions allet any, car je mélange rarement les comparaisons And et Or, cela fonctionne bien et présente l'avantage supplémentaire de ne pas arriver tôt avec la compréhension des générateurs:

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

N'oubliez pas de passer en un seul itérable! Passer des N-arguments n'est pas correct.

Remarque: anyc'est comme beaucoup de orcomparaisons, allc'est comme beaucoup de andcomparaisons.


Cela 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!")

En savoir plus sur: la compréhension du générateur


1
Je dois également souligner que la configuration du stock de pylint veut une indentation en ligne continuation dans un if; ce qui m'a dissuadé d'utiliser ce schéma.
ThorSummoner

2

Et 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

ps J'utilise toujours des tabulations, pas des espaces; Je ne peux pas affiner ...


3
Ce serait très déroutant, surtout lorsque le corps du conditionnel est long, je pense.
Eli Bendersky

Je suis d'accord avec Eli, l'encapsulation et l'indentation ici sont déroutantes pour les longues lignes. De plus, la nouvelle règle est que les instructions andet ordoivent commencer sur la ligne suivante
virtualxtc

2

Ce que je fais habituellement, c'est:

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

de cette façon l'accolade de fermeture et le côlon marquent visuellement la fin de notre condition.


1
Presque correct; PEP 8 recommande désormais de rompre avant andou or.
virtualxtc

2

Tous les répondants qui fournissent également des conditions multiples pour l'instruction if sont tout aussi laids 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

Vous voulez que je mange mes mots? Convainquez-moi que vous avez besoin de multi-conditions et je vais littéralement l'imprimer et le manger pour votre amusement.


c'est en effet une façon très soignée de faire des multi-conditions :) je ne sais pas pourquoi il n'a pas plus de votes :), y a-t-il des mises en garde?
dim_user

@SaulCruz il n'y en a vraiment pas non seulement la variable de condition n'a pas besoin d'être répétée, vous économisez également sur les nombreux doublons de vérification de chaque valeur, cela met simplement uniquement les valeurs dans un tableau et laisse le moteur faire son travail (optimisé) dans vérifier la condition pour vous
Stoff

@Stoff Merci d'avoir supprimé mon commentaire. Je voulais souligner que votre approche ne répond pas à la question du PO. Le code que vous fournissez ne peut pas être appliqué au code de la question. Si vous pensez le contraire, vous devez ajouter le code OP reformaté par votre approche pour prouver votre point.
Jeyekomon

Ce n'est pas la réponse acceptée, mais c'est clairement une approche alternative (d'autres sont d'accord). AINSI encouragé des réponses alternatives alors quel est l'argument exactement? Soyez clair dans votre propre question, envisagez peut-être d'ouvrir votre propre question si vous avez besoin de l'attention appropriée. Ps Je ne suis pas un mod SO, je ne peux pas supprimer les commentaires
Stoff

2

Je pense que la solution de @ zkanda serait bonne avec une petite touche. Si vous aviez vos conditions et valeurs dans leurs propres listes respectives, vous pourriez utiliser une compréhension de liste pour faire la comparaison, ce qui rendrait les choses un peu plus générales pour ajouter 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 comme ceci pour la lisibilité:

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

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

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

if proceed:
    # do something

1
Juste pour le plaisir: all(map(eq, have, expected)). (avec from operator import eq)
Gabriel Garcia

1

Juste quelques autres idées aléatoires par souci d'exhaustivité. S'ils fonctionnent 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 sais pas si cela fonctionne pour vous, mais c'est une autre option à considérer. Voici une autre façon:

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'

Je n'ai pas testé les deux derniers, mais les concepts devraient être suffisants pour vous permettre de continuer si c'est ce que vous voulez.

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


1

J'ai eu du mal à trouver un moyen décent de le faire aussi, alors j'ai juste eu une idée (pas une balle d'argent, car c'est principalement une question de goût).

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

Je trouve quelques mérites dans cette solution par rapport aux autres que j'ai vus, à savoir, vous obtenez exactement 4 espaces supplémentaires d'indentation (bool), permettant à toutes les conditions de s'aligner verticalement, et le corps de l'instruction if peut être indenté dans d'une manière claire (ish). Cela conserve également les avantages de l'évaluation en court-circuit des opérateurs booléens, mais ajoute bien sûr la surcharge d'un appel de fonction qui ne fait essentiellement rien. Vous pourriez argumenter (valablement) que n'importe quelle 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 autre idée, qui supprime les frais généraux d'un appel de fonction. Pourquoi ne pas indiquer que nous allons entrer dans une condition complexe en utilisant des paires de parenthèses supplémentaires? Disons, 2 de plus, pour donner un joli retrait de 2 espaces des sous-conditions par rapport au corps de l'instruction if. Exemple:

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

J'aime un peu ça parce que quand vous le regardez, une cloche sonne immédiatement dans votre tête en disant "hé, il se passe quelque chose de complexe ici!" . Oui, je sais que les parenthèses n'aident pas à la lisibilité, mais ces conditions devraient apparaître assez rarement, et quand elles apparaîtront, vous devrez quand même vous arrêter et les lire attentivement (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 :)


1

Vous pouvez le diviser 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 l'encombrement du if.


1

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 réel est complètement OK? Ce n'est pas "trop ​​indenté?"

... il y a des moments où je souhaite que Python ait mordu la balle et soit parti avec des accolades frisées. Je me demande combien de bugs ont été introduits accidentellement au fil des ans en raison d'une indentation accidentelle ...


0

Mettez vos conditions dans une liste, puis faites un smth. comme:

if False not in Conditions:
    do_something

0

Je trouve que lorsque j'ai de longues conditions, j'ai souvent un corps de code court. Dans ce cas, je viens de double indentation du corps, ainsi:

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

1
@qarma, voudriez-vous vous développer? C'est sûrement mieux que d'utiliser des caractères de continuation de ligne, qui sont recommandés par PEP 8
xorsyst

Il s'agit en fait d'un cas valable pour la poursuite de la ligne. Les parenthèses IMPO signifient un tuple ou un appel de fonction. L'utilisation d'OP est très semblable à C, je préfère la syntaxe python autant que possible. Je reconnais que \ n'est cependant pas universellement favorisé.
Dima Tisnek

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

ou si c'est plus clair:

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

Il n'y a aucune raison que le retrait soit un multiple de 4 dans ce cas, par exemple, voir "Aligné avec le délimiteur d'ouverture":

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


Le guide de Google fournit également un exemple d'une condition complexe , qui correspond à «la façon la plus évidente de le faire», comme mentionné par le PO. Bien que le guide ne préconise pas explicitement le formatage des «si» longs de cette façon.
Anton Strogonoff le

0

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 permet également d'ajouter facilement une autre condition sans modifier l'instruction if en ajoutant simplement une autre condition à la liste:

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

0

J'utilise habituellement:

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

0

si notre condition if & an else doit exécuter plusieurs instructions à l'intérieur, nous pouvons écrire comme ci-dessous. Chaque fois que nous avons sinon un 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

0

Pardonnez ma noblesse, mais il se trouve que je ne connais pas aussi bien #Python que n'importe lequel d'entre vous ici, mais il se trouve que j'ai trouvé quelque chose de similaire lors de l'écriture de mes propres objets dans une modélisation BIM 3D, donc j'adapterai mon algorithme à celui du python.

Le problème que je trouve ici, est double face:

  1. Les valeurs peuvent sembler étrangères à quelqu'un qui pourrait essayer de déchiffrer le script.
  2. La maintenance du code aura un coût élevé, si ces valeurs sont modifiées (le plus probable), ou si de nouvelles conditions doivent être ajoutées (schéma cassé)

Faites pour contourner tous ces problèmes, votre script doit aller comme ça

param_Val01 = Value 01   #give a meaningful name for param_Val(i) preferable an integer
param_Val02 = Value 02
param_Val03 = Value 03
param_Val04 = Value 04   # and ... etc

conditions = 0           # this is a value placeholder

########
Add script that if true will make:

conditions = conditions + param_Val01   #value of placeholder is updated
########

### repeat as needed


if conditions = param_Val01 + param_Val02 + param_Val03 + param_Val04:
    do something

Avantages de cette méthode:

  1. Le script est lisible.

  2. Le script peut être facilement maintenu.

  3. conditions est une opération de comparaison à une somme de valeurs qui représente les conditions souhaitées.
  4. Pas besoin de conditions à plusieurs niveaux

J'espère que cela vous aidera tous

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.