¿Diseñar condiciones de varias líneas en declaraciones 'if'? [cerrado]

677

A veces rompo condiciones largas en ifs en varias líneas. La forma más obvia de hacer esto es:

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

No es muy atractivo visualmente, porque la acción se combina con las condiciones. Sin embargo, es la forma natural usando la sangría correcta de Python de 4 espacios.

Por el momento estoy usando:

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

Pero esto no es muy bonito. :-)

¿Me puede recomendar una forma alternativa?

Eli Bendersky
fuente
2
Si su editor usa el paquete pep8 Python para detectar cuándo advertir sobre violaciones de PEP8 , tendrá que desactivar el error E125 o buscar una solución de formato que satisfaga los pep8criterios del paquete. El problemapep8 del paquete # 126 se trata de arreglar el paquete para seguir estrictamente la especificación PEP8. La discusión sobre el tema incluye algunas sugerencias de estilo que también se ven aquí.
akaihola
1
Tenga en cuenta que para el primer ejemplo, pep8 arrojará "E129 línea visualmente sangrada con la misma sangría que la siguiente línea lógica".
Taylor Edmiston
Esta pregunta es muy antigua y tiene un montón de puntos de vista, pero está inequívocamente basada en opiniones. El lenguaje "no es muy atractivo" y "no es muy bonito" establece el criterio de que la respuesta supuestamente correcta es la que mejor se alinea con la preferencia estética del autor de la pregunta (es decir, una opinión). Podría hacer exactamente la misma pregunta y afirmar que no es un duplicado porque mi gusto estético lo califica como diferente y dará lugar a una respuesta "correcta" diferente.
Z4-tier
@ Z4-tier: sí, está basado en opiniones. Pero se le preguntó hace 12 años. SO era un lugar diferente y más amable en aquel entonces. Recientemente se ha ido acumulando votos negativos desde que los estándares de SO han cambiado. Aún así, habiendo sido visto> 1 millón de veces, espero que esté haciendo más bien que mal en el mundo. Ciertamente puedo ver a la gente preguntándose sobre la misma pregunta hoy, buscándola en Google, aterrizando en esta discusión y encontrando útil calibrar su pensamiento. Hay varias respuestas muy votadas para elegir.
Eli Bendersky
@EliBendersky está completamente de acuerdo. Es como si SO tuviera una crisis de identidad en curso: aunque claramente no se ajusta a "las reglas" (el número de respuestas válidas es un testimonio de eso), es tan claro que agrega valor. En igualdad de condiciones, prefiero trabajar con alguien que haya desarrollado puntos de vista articulados y razonados sobre el estilo de codificación, incluso si sus puntos de vista difieren de los míos.
Z4-tier

Respuestas:

750

No necesita usar 4 espacios en su segunda línea condicional. Tal vez use:

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

Además, no olvide que el espacio en blanco es más flexible de lo que podría pensar:

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

Sin embargo, ambos son bastante feos.

¿Quizás perder los corchetes ( sin embargo, la Guía de estilo desalienta esto)?

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

Esto al menos te da alguna diferenciación.

O incluso:

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

Creo que prefiero:

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

Aquí está la Guía de estilo , que (desde 2010) recomienda usar corchetes.

Harley Holcombe
fuente
45
Tenga en cuenta que PEP no recomienda las soluciones \ finales. Una de las razones es que si se agrega un espacio por error después de una \, es posible que no se muestre en su editor y el código se vuelva sintácticamente incorrecto.
Eric O Lebigot
14
Esto está mal, la guía de estilo dice "Las líneas largas se pueden dividir en varias líneas ajustando las expresiones entre paréntesis. Deben usarse con preferencia al uso de una barra diagonal inversa para la continuación de la línea". Puede ver esto aquí: python.org/dev/peps/pep-0008/#maximum-line-length
joshcartme
8
@joshcartme El PEP cambió en hg.python.org/peps/rev/7a48207aaab6 para desalentar explícitamente las barras invertidas. Actualizaré la respuesta.
Harley Holcombe
3
Gracias, probablemente sea una buena idea actualizar sus ejemplos también, ya que ahora no se recomiendan. Estaba tratando de resolver esto por mí mismo y estaba confundido por la discrepancia entre su respuesta y la guía de estilo (de ahí mi comentario). No solo estaba tratando de ser pedante.
joshcartme
3
PEP 8 ahora desalienta romper después de andy iftambién.
virtualxtc
124

He recurrido a lo siguiente en el caso degenerado en el que se trata simplemente de AND u OR.

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

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

Afeita algunos caracteres y deja en claro que no hay sutileza en la condición.

S.Lott
fuente
44
Este es un enfoque interesante. Sin embargo
Eli Bendersky
20
Está bien si no te importa el cortocircuito.
Constantin
63
shortcirtuiting no siempre se trata de rápido. Aunque no es una buena práctica de codificación, es posible que tenga un código como el existente: if destroy_world and DestroyTheWorld() == world_is_destroyed: .... Genial, ahora acabas de destruir el mundo por accidente. ¿COMO PUDISTE?
Aaron
44
Me sorprende que esto tenga tantos votos positivos. Esta respuesta ignora por completo la pregunta original sobre el diseño de condicionales de varias líneas .
Przemek D
2
Esta expresión no es perezosa. Por lo tanto, no es equivalente si se siguen algunas condiciones de protección por una posible falla.
eugene-bright
57

¡Alguien tiene que defender el uso del espacio en blanco vertical aquí! :)

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

Esto hace que cada condición sea claramente visible. También permite una expresión más limpia de condiciones más complejas:

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

Sí, estamos intercambiando un poco de bienes raíces verticales por claridad. Vale la pena en mi opinión.

Kevin Little
fuente
19
Esto no parece ser hermoso ni compatible con PEP8. PEP8 dice que el lugar preferido para romper alrededor de un operador binario (por ejemplo and, así como or) es después del operador, no antes.
Chris Medrela
77
@ChristopherMedrela ¿dice la razón detrás de eso? Creo que colocar un salto de línea antes del operador lógico es mucho más claro
Norill Tempest
44
Poner el oprerator primero es bastante común en el mundo de los nodos. La razón es que notamos y leemos cosas de la izquierda mucho más rápido que las de la derecha, al menos en las culturas occidentales. Muy válido en JavaScript, donde una coma olvidada puede causar errores silenciosos.
tomekwi
11
No hagas esto por favor. No solo no lo es, PEP8sino que hace que sea más difícil determinar la operación lógica con la que se está encadenando. Rechazaría esto si llegara a mi escritorio a través de la revisión de código.
Urda
11
A partir de la versión actual de PEP8, se considera aceptable romper antes o después de un operador binario , y antes de que el operador se considere mejor para el nuevo código.
Soren Bjornstad
31

Prefiero este estilo cuando tengo una condición si terriblemente grande:

if (
    expr1
    and (expr2 or expr3)
    and hasattr(thingy1, '__eq__')
    or status=="HappyTimes"
):
    do_stuff()
else:
    do_other_stuff()
Deestan
fuente
2
+1 para guardar sangrías donde puedes seguirlas. Me gusta Python y lo uso mucho, pero me molesta constantemente verme obligado a sangrar. La línea múltiple si realmente destruye la estética, incluso cuando se hace bien.
mightypile
44
Tenga en cuenta que tener sus operadores andy oral comienzo de la línea viola PEP 0008 , que establece que "el lugar preferido para romper un operador binario es después del operador, no antes de él". . Sin embargo, me gusta tener el corchete de cierre y los dos puntos en su propia línea para separar la condición if del cuerpo (y es perfectamente posible hacerlo mientras se mantienen los operadores booleanos al final de la línea para cumplir con PEP-0008).
Mark Amery
8
a 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.(el estilo de Knuth es comenzar la línea con el operador).
cowbert
27

Aquí está mi opinión muy personal: las condiciones largas son (en mi opinión) un olor a código que sugiere refactorizar en una función / método de retorno booleano. Por ejemplo:

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

Ahora, si encuentro una manera de hacer que las condiciones de varias líneas se vean bien, probablemente me contentaría con tenerlas y omitir la refactorización.

Por otro lado, hacer que perturben mi sentido estético actúa como un incentivo para la refactorización.

Mi conclusión, por lo tanto, es que las condiciones de varias líneas deben verse feas y esto es un incentivo para evitarlas.

krawyoti
fuente
23

Esto no mejora mucho pero ...

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

if allCondsAreOK:
   do_something
Federico A. Ramponi
fuente
1
Alternativa interesante Pero 2 líneas adicionales :-)
Eli Bendersky
Realmente no funcionaría tan bien en un ciclo iterativo, no funcionaría con funciones haciendo algo ... y para ser justos - feo
Mez
99
Brian, estoy en parte en desacuerdo. El uso de variables para resultados intermedios de un cálculo puede hacer que el código sea más fácil de entender, y en un lenguaje compilado no tendrá ningún impacto en el rendimiento. Probablemente lo haría en Python, aunque no usaría Python en absoluto si el rendimiento fuera tan importante.
Mark Baker,
1
@ MarkBaker Solía ​​estar de acuerdo con lo que escribiste, hasta que leí "Refactoring" de Martin Fowlers. Él proporciona un excelente argumento de que tales variables intermedias causan más daño que beneficio. Inhiben la refactorización posterior. Prescindir de ellos conduce a un estilo de programación más funcional, que se presta bien a la refactorización. Esto me sorprendió, pero creo que tiene razón, y desde entonces me he esforzado por eliminar intermedios innecesarios como este de mi código, incluso si se usan más de una vez.
Jonathan Hartley
2
Bien, pero ¿por qué camelCase? :)
Leonid Shvechikov
19

Sugiero mover la andpalabra clave a la segunda línea y sangrar todas las líneas que contienen condiciones con dos espacios en lugar de cuatro:

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

Así es exactamente como resuelvo este problema en mi código. Tener una palabra clave como la primera palabra en la línea hace que la condición sea mucho más legible, y la reducción del número de espacios distingue aún más la condición de la acción.

DzinX
fuente
99
Leí en algún lugar de Gries o Djikstra que poner el operador lógico al frente de la línea, hacer más visible, ayudó. Y he estado haciendo eso desde los años 90. Y eso ayuda.
S.Lott
77
Tenga en cuenta que la Guía de estilo recomienda colocar el condicional al final de la línea.
Harley Holcombe
3
Eso es cierto, aunque nunca estuve de acuerdo con esto. Es solo una guía, después de todo.
DzinX
8
PEP8 ya no recomienda poner el condicional al final de la línea.
Soren Bjornstad
14

Parece que vale la pena citar PEP 0008 (guía de estilo oficial de Python), ya que comenta sobre este tema con modesta extensión:

Cuando la parte condicional de una ifdeclaración-es lo suficientemente larga como para requerir que se escriba en varias líneas, vale la pena señalar que la combinación de una palabra clave de dos caracteres (es decir if), más un solo espacio, más un paréntesis de apertura crea un 4- natural sangría de espacio para las siguientes líneas del condicional multilínea. Esto puede producir un conflicto visual con el conjunto de código sangrado anidado dentro de la ifdeclaración, que también estaría sangrado naturalmente a 4 espacios. Este PEP no toma una posición explícita sobre cómo (o si) distinguir visualmente dichas líneas condicionales del conjunto anidado dentro de la ifdeclaración. Las opciones aceptables en esta situación incluyen, pero no se limitan a:

# 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()

Tenga en cuenta el "no limitado a" en la cita anterior; Además de los enfoques sugeridos en la guía de estilo, algunos de los sugeridos en otras respuestas a esta pregunta también son aceptables.

Mark Amery
fuente
+1 para PEP8. Esto debería ser aceptado, ya que es (prácticamente hablando) la guía oficial de estilo Python.
Michael - ¿Dónde está Clay Shirky?
2
También vale la pena enfatizar que, PEP8 declara explícitamente su posición ya que este PEP no toma una posición explícita sobre cómo (o si) distinguir visualmente tales líneas condicionales del conjunto anidado dentro de la declaración if. Las opciones aceptables en esta situación incluyen, pero no se limitan a: ... (recortado) ¡ Entonces, deja de discutir, ve con algo que te guste!
RayLuo
7

Esto es lo que hago, recuerde que "todos" y "cualquiera" aceptan un iterable, así que solo pongo una condición larga en una lista y dejo que "todos" hagan el trabajo.

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

if all(condition):
   do_something
zkanda
fuente
4

Me sorprende no ver mi solución preferida,

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

Como andes una palabra clave, mi editor la resalta y se ve lo suficientemente diferente del do_something debajo de ella.

Marius Gedminas
fuente
Pero la línea de continuación aún no se distingue de la siguiente línea lógica ...
Chris Medrela
1
Tenga en cuenta que esta es una violación de PEP 0008 ( "El lugar preferido para romper un operador binario es después del operador, no antes" ). Si te importa, por supuesto, depende de ti.
Mark Amery
1
Por cierto, esta ya no es mi solución preferida. ;)
Marius Gedminas
4

Además de lo que dijo @krawyoti ... Las condiciones largas huelen porque son difíciles de leer y difíciles de entender. El uso de una función o una variable aclara el código. En Python, prefiero usar el espacio vertical, encerrar paréntesis y colocar los operadores lógicos al comienzo de cada línea para que las expresiones no se vean como "flotantes".

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

Si las condiciones deben evaluarse más de una vez, como en un whilebucle, lo mejor es usar una función local.

Apalala
fuente
1
Además de esto, puede declarar una función o una lambda para devolver su verdadero falso en lugar de crear una variable adicional.
Techdragon
@Techdragon si las condiciones van a estar en otro lugar, entonces ponerlas en un bloque lambda requeriría que se nombrara el bloque lambda para que se pueda hacer referencia más adelante en la condición if. Si se va a nombrar una lambda, ¿por qué y no una función regular después de todo? Personalmente, me gusta esta expresión booleana reducida.
Sri Kadimisetty
Estoy de acuerdo, por lo que normalmente usaría una función en la mayoría de los casos para mejorar la legibilidad y la facilidad de la digestión mental al desnatar para comprender el flujo de control del programa. Menciono la lambda para asegurar que la opción 'más pequeña' también esté presente en caso de que las personas sean particularmente conscientes del espacio.
Techdragon
4

Personalmente, me gusta agregar significado a las declaraciones if largas. Tendría que buscar a través del código para encontrar un ejemplo apropiado, pero este es el primer ejemplo que me viene a la mente: supongamos que me encuentro con una lógica peculiar donde quiero mostrar una determinada página dependiendo de muchas variables.

Inglés: "Si el usuario conectado NO es un maestro administrador, sino que es solo un maestro regular y no es un estudiante en sí mismo ..."

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

Claro que esto podría verse bien, pero leer esas declaraciones si es mucho trabajo. ¿Qué tal si asignamos la lógica a la etiqueta que tiene sentido? La "etiqueta" es en realidad el nombre de la variable:

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

Esto puede parecer una tontería, pero es posible que tenga otra condición en la que SOLO quiera mostrar otro elemento si, y solo si, está mostrando el panel del profesor O si el usuario tiene acceso a ese otro panel específico de forma predeterminada:

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

Intente escribir la condición anterior sin usar variables para almacenar y etiquetar su lógica, y no solo termina con una declaración lógica muy desordenada y difícil de leer, sino que también se repite. Si bien hay excepciones razonables, recuerde: no se repita (SECO).

rgenito
fuente
3

"all" y "any" son agradables para las muchas condiciones del mismo tipo de caso. PERO siempre evalúan todas las condiciones. Como se muestra en este ejemplo:

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
Anders Waldenborg
fuente
55
¡Incorrecto! Solo lo hacen porque tú lo haces. Pruebe todo (f () para f en [c1, c2]).
habnabit
2
Creo que estaba usando funciones solo como ejemplo, porque puede hacer que impriman algo fácilmente. Si estamos considerando una serie de expresiones arbitrarias proporcionadas en una lista para all()entonces, a menos que las envuelva en una lambda y utilice su f()truco, todas serán evaluadas. En otras palabras, Aaron: Creo que Anders estaba tratando de hablar sobre las condiciones en general, usando callables como un ejemplo específico; pero su réplica se aplica solo a las funciones.
Brandon Rhodes
3

(Modifiqué ligeramente los identificadores ya que los nombres de ancho fijo no son representativos del código real, al menos no el código real que encuentro, y creo que la legibilidad de un ejemplo).

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

Esto funciona bien para "y" y "o" (es importante que estén primero en la segunda línea), pero mucho menos para otras condiciones largas. Afortunadamente, el primero parece ser el caso más común, mientras que el segundo a menudo se reescribe fácilmente con una variable temporal. (Por lo general, no es difícil, pero puede ser difícil o mucho menos obvio / legible para preservar el cortocircuito de "y" / "o" ​​al reescribir).

Como encontré esta pregunta en tu blog sobre C ++ , incluiré que mi estilo C ++ es idéntico:

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

Simple y simple, también pasa cheques pep8:

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

En los últimos tiempos he estado prefiriendo las funciones ally any, ya que rara vez mezclo las comparaciones And and Or, esto funciona bien y tiene la ventaja adicional de Failing Early con la comprensión de los generadores:

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

¡Solo recuerda pasar en un solo iterable! Pasar N-argumentos no es correcto.

Nota: anyes como muchas orcomparaciones, alles como muchas andcomparaciones.


Esto combina muy bien con las comprensiones del generador, por ejemplo:

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

Más sobre: comprensión del generador

ThorSummoner
fuente
1
También debo señalar que la configuración de stock de pylint quiere una sangría entrante en continuación de línea en un if; lo que me ha disuadido de usar este esquema.
ThorSummoner
2

¿Qué sucede si solo insertamos una línea en blanco adicional entre la condición y el cuerpo y hacemos el resto de forma canónica?

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

    do_something

ps Siempre uso pestañas, no espacios; No puedo afinar ...

Federico A. Ramponi
fuente
3
Esto sería muy confuso, especialmente cuando el cuerpo del condicional es largo, creo.
Eli Bendersky,
Estoy de acuerdo con Eli, la encapsulación y la sangría aquí son confusas para largas colas. Además, la nueva regla es que las declaraciones andy ordeberían comenzar en la siguiente línea
virtualxtc
2

Lo que suelo hacer es:

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

De esta manera, el corsé de cierre y el colon marcan visualmente el final de nuestra condición.

tomekwi
fuente
1
Casi correcto; PEP 8 ahora recomienda romper antes de ando or.
virtualxtc
2

Todos los encuestados que también proporcionan condiciones múltiples para la declaración if son tan feos como el problema presentado. No resuelve este problema haciendo lo mismo ...

Incluso la respuesta PEP 0008 es repulsiva.

Aquí hay un enfoque mucho más legible

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

¿Quieres que me coma mis palabras? Convénceme de que necesitas múltiples condicionales y literalmente imprimiré esto y me lo comeré para tu diversión.

Stoff
fuente
esta es de hecho una forma muy ordenada de hacer multicondicionales :) no sé por qué no tiene más votos :), ¿hay alguna advertencia?
dim_user
@SaulCruz realmente no existe No solo no es necesario repetir la variable de condición, sino que también guarda en los muchos duplicados de verificar cada valor, esto simplemente coloca los valores en una matriz y deja que el motor haga su trabajo (optimizado) comprobando la condición para usted
Stoff
@Stoff Gracias por eliminar mi comentario. Quería señalar que su enfoque no responde a la pregunta del OP. El código que proporcione no se puede aplicar al código en la pregunta. Si piensa lo contrario, entonces debe agregar el código de OP reformateado por su enfoque para probar su punto.
Jeyekomon
No es la respuesta aceptada, sin embargo, es claramente un enfoque alternativo (otros están de acuerdo). SO alentó respuestas alternativas, ¿cuál es exactamente el argumento? Sea claro en su propia pregunta, quizás considere abrir su propia pregunta si requiere la atención adecuada. Ps no soy un mod lo tanto, no puedo eliminar los comentarios
Stoff
2

Creo que la solución de @ zkanda sería buena con un pequeño giro. Si tuviera sus condiciones y valores en sus propias listas respectivas, podría usar una comprensión de la lista para hacer la comparación, lo que haría las cosas un poco más generales para agregar pares de condición / valor.

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

Si quisiera codificar una declaración como esta, la escribiría así para que sea legible:

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

Y solo para lanzar otra solución con un iandoperador :

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

if proceed:
    # do something
ryanjdillon
fuente
1
Sólo por diversión: all(map(eq, have, expected)). (con from operator import eq)
Gabriel Garcia
1

Solo algunas otras ideas aleatorias para completar. Si funcionan para ti, úsalos. De lo contrario, probablemente sea mejor que intentes otra cosa.

También puedes hacer esto con un diccionario:

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

Esta opción es más complicada, pero también puede resultarle útil:

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

No sé si eso funciona para usted, pero es otra opción a considerar. Aquí hay una forma más:

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'

Los dos últimos no los he probado, pero los conceptos deberían ser suficientes para ponerlo en marcha si eso es lo que desea.

(Y para que conste, si esto es solo una vez, probablemente sea mejor que uses el método que presentaste al principio. Si estás haciendo la comparación en muchos lugares, estos métodos pueden mejorar la legibilidad lo suficiente como para hacer no te sientes tan mal por el hecho de que son un poco hacky).

Jason Baker
fuente
1

He estado luchando por encontrar una forma decente de hacer esto también, así que se me ocurrió una idea (no una bala de plata, ya que esto es principalmente una cuestión de gustos).

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

Encuentro algunos méritos en esta solución en comparación con otros que he visto, a saber, obtienes exactamente 4 espacios adicionales de sangría (bool), permitiendo que todas las condiciones se alineen verticalmente, y el cuerpo de la declaración if puede sangrarse en una manera clara (ish) Esto también mantiene los beneficios de la evaluación de cortocircuito de los operadores booleanos, pero, por supuesto, agrega la sobrecarga de una llamada de función que básicamente no hace nada. Se podría argumentar (válidamente) que cualquier función que devuelva su argumento podría usarse aquí en lugar de bool, pero como dije, es solo una idea y, en última instancia, es cuestión de gustos.

Curiosamente, mientras escribía esto y pensaba en el "problema", se me ocurrió otra idea, que elimina la sobrecarga de una llamada de función. ¿Por qué no indicar que estamos a punto de entrar en una condición compleja mediante el uso de pares de paréntesis adicionales? Digamos 2 más para dar una buena sangría de 2 espacios de las subcondiciones relativas al cuerpo de la declaración if. Ejemplo:

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

Me gusta esto porque cuando lo miras, inmediatamente suena una campana en tu cabeza que dice "¡Oye, hay algo complejo aquí!" . Sí, sé que los paréntesis no ayudan a la legibilidad, pero estas condiciones deberían aparecer raramente, y cuando aparezcan, tendrás que detenerte y leerlas con cuidado de todos modos (porque son complejas ).

De todos modos, solo dos propuestas más que no he visto aquí. Espero que esto ayude a alguien :)

El Ninja Trepador
fuente
1

Podrías dividirlo en dos líneas.

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

O incluso agregar una condición a la vez. De esa manera, al menos separa el desorden del if.

SarcásticoSully
fuente
1

Sé que este hilo es antiguo, pero tengo un código Python 2.7 y PyCharm (4.5) todavía se queja de este caso:

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

Incluso con la advertencia PEP8 "línea visualmente sangrada con la misma sangría que la siguiente línea lógica", ¿el código real está completamente bien? No es "sobre-sangría?"

... hay veces que desearía que Python hubiera mordido la bala y se hubiera ido con llaves. Me pregunto cuántos errores se han introducido accidentalmente a lo largo de los años debido a una indentación accidental ...

SMGreenfield
fuente
0

Empaque sus condiciones en una lista, luego haga algo. me gusta:

if False not in Conditions:
    do_something
psihodelia
fuente
0

Encuentro que cuando tengo condiciones largas, a menudo tengo un cuerpo de código corto. En ese caso, solo sangro dos veces el cuerpo, por lo tanto:

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'):
        do_something
xorsyst
fuente
1
@ qarma, ¿te gustaría expandirte? Seguramente es mejor que usar caracteres de continuación de línea, que se recomiendan en contra de PEP 8
xorsyst
De hecho, este es un caso válido para la continuación de línea. Los paréntesis de IMPO significan una tupla o una llamada de función. El uso de OP es muy similar a C, prefiero la sintaxis de Python siempre que sea posible. Sin embargo, reconozco que no está universalmente favorecido.
Dima Tisnek
0
  if cond1 == 'val1' and \
     cond2 == 'val2' and \
     cond3 == 'val3' and \
     cond4 == 'val4':
      do_something

o si esto es más claro:

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

No hay ninguna razón por la que la sangría deba ser un múltiplo de 4 en este caso, por ejemplo, consulte "Alineado con delimitador de apertura":

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

Dima Tisnek
fuente
La guía de Google también proporciona un ejemplo de una condición compleja , que coincide con "la forma más obvia de hacer esto" como lo menciona el OP. Aunque la guía no recomienda explícitamente formatear largos "si" es así.
Anton Strogonoff
0

Aquí hay otro enfoque:

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

Esto también hace que sea fácil agregar otra condición fácilmente sin cambiar la instrucción if simplemente agregando otra condición a la lista:

cond_list.append('cond5=="val5"')
usuario1487551
fuente
0

Usualmente uso:

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

si nuestra condición if & an else tiene que ejecutar varias instrucciones dentro de ella, entonces podemos escribir como a continuación. Cada vez que tenemos un ejemplo if else con una declaración dentro de ella.

Gracias funciona para mi.

#!/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
Laxman G
fuente
0

Disculpe mi novato, pero sucede que no estoy tan bien informado sobre #Python como cualquiera de ustedes aquí, pero sucede que he encontrado algo similar al escribir mis propios objetos en un modelado 3D BIM, por lo que adaptaré mi algoritmo a el de python.

El problema que encuentro aquí es de doble cara:

  1. Los valores pueden parecer extraños para alguien que intente descifrar el guión.
  2. El mantenimiento del código tendrá un alto costo, si esos valores se cambian (lo más probable), o si se deben agregar nuevas condiciones (esquema roto)

Para evitar todos estos problemas, su script debe ser así

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

Ventajas de este método:

  1. El guión es legible.

  2. La secuencia de comandos se puede mantener fácilmente.

  3. condiciones es una operación de comparación 1 a una suma de valores que representa las condiciones deseadas.
  4. No hay necesidad de condiciones multinivel

Espero que les ayude a todos

Nader Belal
fuente