Parfois, je casse de longues conditions dans if
s 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, parce que l’action se confond avec les conditions. Cependant, c’est la méthode naturelle qui consiste à utiliser une bonne indentation Python 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 un autre moyen?
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
De plus, n'oubliez pas que les espaces sont plus flexibles 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 moche cependant.
Peut-être perdre les crochets (le Style Guide décourage cependant cela)?
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 l’utilisation de crochets.
J'ai eu recours à ce qui suit dans le cas dégénéré où il s'agit simplement d'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 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 la peine IMO.
Voici mon point de vue personnel: les longues conditions sont (à mon avis) une odeur de code qui suggère de refactoriser dans 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 un moyen de rendre bonnes les conditions multilignes, je me contenterais probablement de les avoir et d'éviter le refactoring.
D'autre part, leur perturbation mon sens esthétique agit comme une incitation à la refactorisation.
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 quand j'ai un si grand état si:
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 le mot clé and
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 comme cela que 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 de manière modeste:
Lorsque la partie conditionnelle d'une instruction
if
est suffisamment longue pour exiger son écriture sur plusieurs lignes, il est intéressant de noter que la combinaison d'un mot clé à deux caractères (ieif
), d'un espace unique et d'une parenthèse ouvrante crée Retrait de 4 espaces pour les lignes suivantes du multiligne conditionnel. Cela peut produire un conflit visuel avec la suite de code indentée imbriquée dans l'instructionif
, qui serait aussi 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'instructionif
. 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 le "non 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 "tous" acceptent les valeurs éditables, alors je mets simplement une longue condition dans une liste et laisse "tous" 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
Étant donné que and
est un mot clé, il est mis en évidence par mon éditeur et est 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 étrange dans laquelle je veux afficher une certaine page en fonction de nombreuses variables.
Anglais: "Si l'utilisateur connecté n'est PAS un enseignant administrateur, mais bien un enseignant régulier et 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 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 OR 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. Non seulement vous obtenez une instruction logique très compliquée 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).
En plus de 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 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 boucle while
, il est préférable d'utiliser une fonction locale.
"all" et "any" conviennent aux 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 pas du code réel que je rencontre - et vont 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 "ou" (il est important qu'ils soient en première position sur la deuxième ligne), mais beaucoup moins pour d'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-circuit de "et"/"ou" lors de la réécriture.)
Depuis que j'ai trouvé cette question dans votre billet 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
}
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 and Or et que cela fonctionne bien.
if all([
cond1,
cond2,
]):
print("Hello World!")
N'oubliez pas de passer dans un seul itérable! Passer dans N-arguments n'est pas correct.
Remarque: any
est semblable à beaucoup de comparaisons or
, all
est semblable à beaucoup de comparaisons and
.
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!")
Plus sur: compréhension du générateur
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
p.s. J'utilise toujours des tabulations, pas des espaces; Je ne peux pas peaufiner ...
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, 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 la déclaration if peut être indenté dans une voie claire (ish). Cela conserve également les avantages de l’évaluation de court-circuit des opérateurs booléens, mais ajoute évidemment la surcharge d’un appel de fonction qui ne fait fondamentalement rien. Vous pourriez 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 l’idée de encore une autre 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 retrait de Nice 2 espace des sous-conditions relatives au corps de l'instruction if. Exemple:
if (((foo and
bar and
frob and
ninja_bear))):
do_stuff()
J'aime bien ça parce que quand vous le regardez, une cloche sonne immédiatement dans votre tête en disant (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, lorsqu'elles apparaissent, vous devrez 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 vu ici. J'espère que ça aide quelqu'un :)
Juste quelques autres idées aléatoires pour la perfection. S'ils travaillent pour vous, utilisez-les. Sinon, vous feriez probablement mieux d'essayer autre chose.
Vous pouvez aussi 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 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 n'ont pas encore été testés, mais les concepts devraient suffire à vous lancer, si c'est ce que vous voulez faire.
(Et pour mémoire, s’il s’agit d’une chose ponctuelle, 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é suffisamment vous ne vous sentez pas si mal à propos du fait qu'ils sont un peu hacky.)
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 cela sépare le fouillis de la if
.
Je sais que ce fil est ancien, mais j'ai du code Python 2.7 et PyCharm (4.5) se plaint toujours de cette affaire:
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 indentée visuellement 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 cours des années en raison d'une erreur d'indentation accidentelle ...
Je pense que la solution de @ zkanda serait bonne avec une légère modification. Si vos conditions et vos valeurs figurent dans leurs propres listes respectives, vous pouvez utiliser une compréhension de liste pour faire la comparaison, ce qui rendrait les choses un peu plus générales pour l'ajout de 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 opérateur iand
:
proceed = True
for c, v in Zip(conditions, values):
proceed &= c==v
if proceed:
# do something
si notre condition if & an else doit exécuter plusieurs instructions à l'intérieur, nous pouvons écrire comme ci-dessous .
Merci cela fonctionne 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
Je trouve que quand j'ai de longues conditions, j'ai souvent un corps de code court. Dans ce cas, je double-indenter le corps, ainsi:
if (cond1 == 'val1' and cond2 == 'val2' and
cond3 == 'val3' and cond4 == 'val4'):
do_something
J'utilise habituellement:
if ((cond1 == 'val1' and cond2 == 'val2' and
cond3 == 'val3' and cond4 == 'val4')):
do_something()
Emballez vos conditions dans une liste, puis faites-le. comme:
if False not in Conditions:
do_something
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
Tu veux que je mange mes mots? Convainquez-moi que vous avez besoin de plusieurs conditions et je vais littéralement l'imprimer et le manger pour votre divertissement.
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"')
Je suppose que quelque chose comme ceci est l'option la plus lisible:
for pet in Zoo:
cute = every_pet()
furry = hair is 'over9000'
small = size < min_size
if cute and furry and small:
return 'I need to feed it!'
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é avec le séparateur d'ouverture":
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Indentation#Indentation