Pregunta

A veces rompo las condiciones largas en if s 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 de usar la sangría Python correcta 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. :-)

¿Puedes recomendar una forma alternativa?

¿Fue útil?

Solución

No es necesario que uses 4 espacios en tu segunda línea condicional. Tal vez utilice:

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

Además, no olvides que el espacio en blanco es más flexible de lo que piensas:

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.

Tal vez pierda los corchetes (la Guía de estilo desalienta esto sin embargo)?

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 utilizar corchetes.

Otros consejos

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 claro que no hay sutileza en la condición.

¡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. Bien vale la pena IMO.

Esta es 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 multilínea se vean bien, probablemente me sentiré contento de tenerlas y me saltaré la refactorización.

Por otra parte, hacer que perturben mi sentido estético actúa como un incentivo para refactorizar.

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

Esto no mejora mucho pero ...

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

if allCondsAreOK:
   do_something

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

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

Sugiero mover la palabra clave y 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 soluciono 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 reducir el número de espacios distingue más la condición de la acción.

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

  

Cuando la parte condicional de una declaración if 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, si ), más un solo espacio, más un paréntesis de apertura crea una sangría natural de 4 espacios para las siguientes líneas del condicional multilínea. Esto puede generar un conflicto visual con el conjunto de código sangrado anidado dentro de la declaración if , que también se sangraría naturalmente en 4 espacios. Este PEP no toma una posición explícita sobre cómo (o si) distinguir más visualmente dichas líneas condicionales de la suite anidada dentro de la declaración si . 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 que " no se limita 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.

Esto es lo que hago, recuerda que " todo " y " cualquier " acepta una iterable, así que solo puse una condición larga en una lista y dejé que " todo " hacer el trabajo.

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

if all(condition):
   do_something

Me sorprende no ver mi solución preferida,

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

Dado que y es una palabra clave, mi editor lo resalta y se ve lo suficientemente diferente del do_something debajo de él.

Personalmente, me gusta agregar significado a sentencias if largas. Tendría que buscar en el código para encontrar un ejemplo apropiado, pero este es el primer ejemplo que me viene a la mente: digamos que me encuentro con alguna lógica peculiar en la que quiero mostrar una página determinada dependiendo de muchas variables.

Inglés: " Si el usuario que ha iniciado sesión 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 puede verse bien, pero leer esas afirmaciones 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 desee 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 complicada y difícil de leer, sino que también se repite. Si bien hay excepciones razonables, recuerde: no se repita (DRY).

" todo " y " cualquier " 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

(He modificado ligeramente los identificadores, ya que los nombres de ancho fijo no son representativos del código real, al menos no del código real que encuentro, y desmienten 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 sean los primeros en la segunda línea), pero mucho menos para otras condiciones prolongadas. Afortunadamente, el primero parece ser el caso más común, mientras que el segundo suele ser fácilmente reescrito con una variable temporal. (Por lo general, no es difícil, pero puede ser difícil o mucho menos obvio / legible conservar el cortocircuito de " y " / " o " al volver a escribir).

Desde que encontré esta pregunta de tu publicación de blog sobre C ++ , incluiré que mi estilo de C ++ es idéntico:

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

Agregando a lo que dijo @krawyoti ... Las condiciones duras huelen porque son difíciles de leer y de entender. El uso de una función o una variable hace que el código sea más claro. 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 "flotando".

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 while , lo mejor es usar una función local.

Simple y simple, también pasa cheques pep8:

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

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

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

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

Nota: any es como muchas comparaciones de o , all es como muchas comparaciones de y .


Esto se combina 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 información sobre: ?? comprensión del generador

¿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

p.s. Siempre uso tabulaciones, no espacios; No puedo afinar ...

Solo algunas otras ideas aleatorias para completar. Si funcionan para ti, úsalos. De lo contrario, probablemente sea mejor que pruebes algo más.

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 ti, pero es otra opción a considerar. Aquí hay una manera 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 ponerte en marcha si eso es lo que quieres.

(Y para el registro, si esto es solo una vez, probablemente esté mejor usando el método que presentó al principio. Si está haciendo la comparación en muchos lugares, estos métodos pueden mejorar la legibilidad lo suficiente como para que no te sientas tan mal por el hecho de que son un poco tontas.)

Lo que suelo hacer es:

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

de esta manera, el corsé y los dos puntos de cierre marcan visualmente el final de nuestra condición.

También he estado luchando para encontrar una manera decente de hacer esto, 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, es decir, obtienes exactamente 4 espacios adicionales de sangría (bool), lo que permite que todas las condiciones se alineen verticalmente, y el cuerpo de la sentencia if puede ser sangrado de una manera clara (ish) Esto también mantiene los beneficios de la evaluación en corto circuito de operadores booleanos, pero, por supuesto, agrega la sobrecarga de una llamada de función que básicamente no hace nada. 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 una cuestión de gusto.

Bastante cómico, mientras escribía esto y pensaba en el "problema", se me ocurrió otra idea, lo que elimina la sobrecarga de una llamada de función. ¿Por qué no indicar que estamos a punto de ingresar a una condición compleja utilizando pares de paréntesis adicionales? Diga, 2 más, para dar una bonita sangría de 2 espacios de las sub-condiciones relativas al cuerpo de la sentencia if. Ejemplo:

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

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

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

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 en una condición a la vez. De esa manera, al menos separa el desorden del if .

Sé que este hilo es antiguo, pero tengo algo de código de Python 2.7 y PyCharm (4.5) aún 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 con sangría visual con la misma sangría que la siguiente línea lógica " ;, ¿el código real está completamente bien? No es " sangrado excesivo? & Quot;

... hay veces en 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 sangría accidental ...

Todos los encuestados que también proporcionan condicionales múltiples para la sentencia if son tan feos como el problema presentado. No resuelves este problema haciendo lo mismo ...

Incluso la respuesta del PEP 0008 es repulsiva.

Este es 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 coma mis palabras? Convénceme en que necesitas múltiples condicionales y, literalmente, imprimiré esto y lo comeré para tu diversión.

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 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 iand operador :

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

if proceed:
    # do something

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

if False not in Conditions:
    do_something

Encuentro que cuando tengo condiciones prolongadas, a menudo tengo un cuerpo de código corto. En ese caso, simplemente sangré el cuerpo, por lo que:

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

o si esto es más claro:

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

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

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

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"')

Normalmente uso:

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

si nuestro if & amp; una condición else tiene que ejecutar varias sentencias dentro de la que podemos escribir como a continuación. Cada vez que tenemos otro ejemplo con una declaración dentro de él.

Gracias, funciona para mí.

#!/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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top