if-statement != - El equivalente de Python de &&(lógico-y)en una sentencia if




que significa (9)

Aquí está mi código:

def front_back(a, b):
  # +++your code here+++
  if len(a) % 2 == 0 && len(b) % 2 == 0:
    return a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):] 
  else:
    #todo! Not yet done. :P
  return

Estoy recibiendo un error en el condicional IF. ¿Qué estoy haciendo mal?


Answers

Estoy recibiendo un error en el condicional IF. ¿Qué estoy haciendo mal?

La razón por la que obtiene un SyntaxError es que no hay un operador && en Python. Igualmente || y ! No son operadores Python válidos .

Algunos de los operadores que conoces de otros idiomas tienen un nombre diferente en Python. Los operadores lógicos && y || En realidad se llaman yy or . Igualmente el operador lógico de negación ! Se llama not .

Así que podrías escribir:

if len(a) % 2 == 0 and len(b) % 2 == 0:

o incluso:

if not (len(a) % 2 or len(b) % 2):

Alguna información adicional (que podría ser útil):

Resumí el operador "equivalentes" en esta tabla:

+------------------------------+---------------------+
|  Operator (other languages)  |  Operator (Python)  |
+==============================+=====================+
|              &&              |         and         |
+------------------------------+---------------------+
|              ||              |         or          |
+------------------------------+---------------------+
|              !               |         not         |
+------------------------------+---------------------+

Véase también la documentación de Python: 6.11. Operaciones booleanas .

Además de los operadores lógicos, Python también tiene operadores bitwise / binary:

+--------------------+--------------------+
|  Logical operator  |  Bitwise operator  |
+====================+====================+
|        and         |         &          |
+--------------------+--------------------+
|         or         |         |          |
+--------------------+--------------------+

No hay una negación a nivel de bits en Python (solo el operador inverso a nivel de bits ~ , pero eso no es equivalente a not ).

Ver también 6.6. Aritmética unaria y operaciones bitwise / binarias y 6.7. Operaciones aritméticas binarias .

Los operadores lógicos (como en muchos otros idiomas) tienen la ventaja de que están cortocircuitados. Eso significa que si el primer operando ya define el resultado, entonces el segundo operador no se evalúa en absoluto.

Para mostrar esto, uso una función que simplemente toma un valor, lo imprime y lo devuelve de nuevo. Esto es útil para ver qué se evalúa realmente debido a las declaraciones impresas:

>>> def print_and_return(value):
...     print(value)
...     return value

>>> res = print_and_return(False) and print_and_return(True)
False

Como se puede ver, solo se ejecuta una instrucción de impresión, por lo que Python ni siquiera miró el operando correcto.

Este no es el caso de los operadores binarios. Los que siempre evalúan ambos operandos:

>>> res = print_and_return(False) & print_and_return(True);
False
True

Pero si el primer operando no es suficiente, entonces, por supuesto, se evalúa al segundo operador:

>>> res = print_and_return(True) and print_and_return(False);
True
False

Para resumir esto aquí hay otra tabla:

+-----------------+-------------------------+
|   Expression    |  Right side evaluated?  |
+=================+=========================+
| `True` and ...  |           Yes           |
+-----------------+-------------------------+
| `False` and ... |           No            |
+-----------------+-------------------------+
|  `True` or ...  |           No            |
+-----------------+-------------------------+
| `False` or ...  |           Yes           |
+-----------------+-------------------------+

El True y el False representan lo que devuelve bool(left-hand-side) , no tienen que ser True o False , solo necesitan devolver True o False cuando se les llama a bool (1).

Así que en Pseudo-Code (!), Las funciones and y or funcionan de la siguiente manera:

def and(expr1, expr2):
    left = evaluate(expr1)
    if bool(left):
        return evaluate(expr2)
    else:
        return left

def or(expr1, expr2):
    left = evaluate(expr1)
    if bool(left):
        return left
    else:
        return evaluate(expr2)

Tenga en cuenta que este es un pseudocódigo, no un código de Python. En Python no puede crear funciones llamadas or porque estas son palabras clave. Además, nunca debes usar "evaluar" o if bool(...) .

Personalizando el comportamiento de tus propias clases.

Esta llamada bool implícita se puede usar para personalizar cómo se comportan tus clases con and , or not .

Para mostrar cómo se puede personalizar, utilizo esta clase que, de nuevo, print algo para rastrear lo que está sucediendo:

class Test(object):
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        print('__bool__ called on {!r}'.format(self))
        return bool(self.value)

    __nonzero__ = __bool__  # Python 2 compatibility

    def __repr__(self):
        return "{self.__class__.__name__}({self.value})".format(self=self)

Así que veamos qué pasa con esa clase en combinación con estos operadores:

>>> if Test(True) and Test(False):
...     pass
__bool__ called on Test(True)
__bool__ called on Test(False)

>>> if Test(False) or Test(False):
...     pass
__bool__ called on Test(False)
__bool__ called on Test(False)

>>> if not Test(True):
...     pass
__bool__ called on Test(True)

Si no tiene un método __bool__ , Python también verifica si el objeto tiene un método __len__ y si devuelve un valor mayor que cero. Puede ser útil saberlo en caso de que cree un contenedor de secuencia.

Ver también 4.1. Prueba de valor de verdad .

NumPy matrices y subclases

Probablemente un poco más allá del alcance de la pregunta original, pero en caso de que estés tratando con arrays o subclases NumPy (como Pandas Series o DataFrames), entonces la llamada bool implícita elevará el temido ValueError :

>>> import numpy as np
>>> arr = np.array([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

>>> import pandas as pd
>>> s = pd.Series([1,2,3])
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> s and s
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

En estos casos, puede usar la función lógica y de NumPy que realiza un elemento and (o or ):

>>> np.logical_and(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([False, False,  True, False])
>>> np.logical_or(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([ True, False,  True,  True])

Si está tratando solo con matrices booleanas , también podría usar los operadores binarios con NumPy, estos realizan comparaciones de elementos (pero también binarias):

>>> np.array([False,False,True,True]) & np.array([True, False, True, False])
array([False, False,  True, False])
>>> np.array([False,False,True,True]) | np.array([True, False, True, False])
array([ True, False,  True,  True])

(1)

Que la llamada bool en los operandos tenga que devolver True o False no es completamente correcto. Es solo el primer operando que necesita devolver un booleano en su método __bool__ :

class Test(object):
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        return self.value

    __nonzero__ = __bool__  # Python 2 compatibility

    def __repr__(self):
        return "{self.__class__.__name__}({self.value})".format(self=self)

>>> x = Test(10) and Test(10)
TypeError: __bool__ should return bool, returned int
>>> x1 = Test(True) and Test(10)
>>> x2 = Test(False) and Test(10)

Esto se debe a que, de hecho, devuelve el primer operando si el primer operando se evalúa como False y si se evalúa como True , devuelve el segundo operando:

>>> x1
Test(10)
>>> x2
Test(False)

Del mismo modo para or pero al revés:

>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)

Sin embargo, si los usa en una declaración if , if también llamará implícitamente a bool en el resultado. Por lo tanto, estos puntos más finos pueden no ser relevantes para usted.


Usted querría and lugar de && .


tal vez con & en lugar de% es más rápido y se mantiene la legibilidad

otras pruebas par / impar

x es par? x% 2 == 0

x es impar? no x% 2 == 0

Tal vez sea más claro con bitwise y 1

x es impar? x & 1

x es par? no x & 1 (no impar)

def front_back(a, b):
    # +++your code here+++
    if not len(a) & 1 and not len(b) & 1:
        return a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):] 
    else:
        #todo! Not yet done. :P
    return

Dos comentarios:

  • Utilice and or para operaciones lógicas en Python.
  • Usa 4 espacios para sangrar en lugar de 2. Te lo agradecerás más tarde porque tu código se verá más o menos igual que el código de todos los demás. Ver PEP 8 para más detalles.

Fui con una solución puramente matemática:

def front_back(a, b):
  return a[:(len(a)+1)//2]+b[:(len(b)+1)//2]+a[(len(a)+1)//2:]+b[(len(b)+1)//2:]

Python usa yy condicionales.

es decir

if foo == 'abc' and bar == 'bac' or zoo == '123':
  # do something

Utiliza and or para realizar operaciones lógicas como en C, C ++. Como literalmente and es && y or es || .

Echa un vistazo a este divertido ejemplo,

Digamos que quieres construir puertas lógicas en Python:

def AND(a,b):
    return (a and b) #using and operator

def OR(a,b):
    return (a or b)  #using or operator

Ahora trata de llamarlos:

print AND(False, False)
print OR(True, False)

Esto dará como resultado:

False
True

¡Espero que esto ayude!


Probablemente este no sea el mejor código para esta tarea, pero está funcionando.

def front_back(a, b):

 if len(a) % 2 == 0 and len(b) % 2 == 0:
    print a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):]

 elif len(a) % 2 == 1 and len(b) % 2 == 0:
    print a[:(len(a)/2)+1] + b[:(len(b)/2)] + a[(len(a)/2)+1:] + b[(len(b)/2):] 

 elif len(a) % 2 == 0 and len(b) % 2 == 1:
     print a[:(len(a)/2)] + b[:(len(b)/2)+1] + a[(len(a)/2):] + b[(len(b)/2)+1:] 

 else :
     print a[:(len(a)/2)+1] + b[:(len(b)/2)+1] + a[(len(a)/2)+1:] + b[(len(b)/2)+1:]

Estoy unos años atrasados ​​aquí, pero:

En 'Editar 4/5/6' de la publicación original, estás usando la construcción:

$ /usr/bin/time cat big_file | program_to_benchmark

Esto está mal en un par de maneras diferentes:

  1. En realidad estás cronometrando la ejecución de `cat`, no tu punto de referencia. El uso de CPU de "usuario" y "sys" mostrado por "tiempo" son los de "cat", no su programa de referencia. Peor aún, el tiempo 'real' tampoco es necesariamente exacto. Dependiendo de la implementación de `cat` y de las tuberías en su sistema operativo local, es posible que` cat` escriba un búfer gigante final y salga mucho antes de que el proceso del lector finalice su trabajo.

  2. El uso de `cat` es innecesario y, de hecho, contraproducente; Estás agregando partes móviles. Si estaba en un sistema suficientemente antiguo (es decir, con una sola CPU y, en ciertas generaciones de computadoras, I / O más rápido que la CPU), el simple hecho de que "cat" se estuviera ejecutando podría influir sustancialmente en los resultados. También está sujeto a lo que pueda hacer el búfer de entrada y salida y otro procesamiento que pueda hacer `cat`. (Es probable que esto te gane un premio de "Uso inútil de gato" si yo fuera Randal Schwartz.

Una mejor construcción sería:

$ /usr/bin/time program_to_benchmark < big_file

En esta declaración, es el shell que abre big_file, pasándolo a su programa (bueno, en realidad a `time` que luego ejecuta su programa como un subproceso) como un descriptor de archivo ya abierto. El 100% de la lectura del archivo es estrictamente responsabilidad del programa que está tratando de evaluar. Esto le da una lectura real de su rendimiento sin complicaciones espurias.

Mencionaré dos 'arreglos' posibles, pero en realidad incorrectos, que también podrían considerarse (pero los 'numeré' de manera diferente, ya que no son cosas que estaban mal en la publicación original):

A. Puedes 'arreglar' esto programando solo tu programa:

$ cat big_file | /usr/bin/time program_to_benchmark

B. o cronometrando todo el oleoducto:

$ /usr/bin/time sh -c 'cat big_file | program_to_benchmark'

Estos son incorrectos por las mismas razones que en el # 2: todavía están usando `cat` innecesariamente. Los menciono por algunas razones:

  • son más "naturales" para las personas que no están del todo cómodas con las funciones de redirección de E / S del shell POSIX

  • puede haber casos en los que se necesite `cat` (por ejemplo: el archivo que se va a leer requiere algún tipo de privilegio para acceder, y usted no quiere otorgar ese privilegio al programa para ser evaluado:` sudo cat / dev / sda | / usr / bin / time my_compression_test --no-output`)

  • en la práctica , en las máquinas modernas, el agregado 'cat' en la tubería probablemente no tenga consecuencias reales

Pero digo eso último con cierta vacilación. Si examinamos el último resultado en 'Editar 5' -

$ /usr/bin/time cat temp_big_file | wc -l
0.01user 1.34system 0:01.83elapsed 74%CPU ...

- esto afirma que 'cat' consumió el 74% de la CPU durante la prueba; y de hecho 1.34 / 1.83 es ​​aproximadamente 74%. Quizás una racha de:

$ /usr/bin/time wc -l < temp_big_file

¡Habría tomado solo los restantes .49 segundos! Probablemente no: `cat` aquí tuvo que pagar por las llamadas del sistema read () (o equivalente) que transfirieron el archivo desde el 'disco' (en realidad caché de búfer), así como las escrituras de canalizaciones para entregarlas a` wc`. La prueba correcta todavía habría tenido que hacer esas llamadas de lectura (); solo las llamadas de escritura a la tubería y de lectura desde la tubería se habrían guardado, y esas deberían ser bastante baratas.

Sin embargo, predigo que sería capaz de medir la diferencia entre `cat cat | wc -l` y `wc -l <file` y encuentre una diferencia notable (porcentaje de 2 dígitos). Cada una de las pruebas más lentas habrá pagado una multa similar en tiempo absoluto; lo que sin embargo equivaldría a una fracción menor de su tiempo total mayor.

De hecho, hice algunas pruebas rápidas con un archivo de 1.5 gigabytes de basura, en un sistema Linux 3.13 (Ubuntu 14.04), obteniendo estos resultados (estos son en realidad los mejores resultados de 3; después de cebar el caché, por supuesto):

$ time wc -l < /tmp/junk
real 0.280s user 0.156s sys 0.124s (total cpu 0.280s)
$ time cat /tmp/junk | wc -l
real 0.407s user 0.157s sys 0.618s (total cpu 0.775s)
$ time sh -c 'cat /tmp/junk | wc -l'
real 0.411s user 0.118s sys 0.660s (total cpu 0.778s)

Tenga en cuenta que los dos resultados de la canalización afirman haber consumido más tiempo de CPU (usuario + sistemas) que en tiempo real. Esto se debe a que estoy usando el comando 'time' incorporado en el shell (Bash), que es consciente de la tubería; y estoy en una máquina multi-core donde procesos separados en una tubería pueden usar núcleos separados, acumulando tiempo de CPU más rápido que en tiempo real. Al usar / usr / bin / time, veo un tiempo de CPU más pequeño que en tiempo real, lo que demuestra que solo puede medir el tiempo que el elemento de canalización pasado pasa a su línea de comando. Además, la salida del shell da milisegundos, mientras que / usr / bin / time solo da cientos de segundos.

Entonces, en el nivel de eficiencia de `wc -l`, el` cat` hace una gran diferencia: 409/283 = 1.453 o 45.3% más en tiempo real, y 775/280 = 2.768, o un 177% más de CPU utilizada! En mi caja de prueba al azar estaba allí en el tiempo.

Debo agregar que hay al menos otra diferencia significativa entre estos estilos de prueba, y no puedo decir si es un beneficio o una falla; Usted tiene que decidir esto usted mismo:

Cuando ejecutas `cat big_file | / usr / bin / time my_program`, su programa recibe información de una tubería, exactamente al ritmo enviado por `cat`, y en partes no mayores que las escritas por` cat`.

Cuando ejecuta `/ usr / bin / time my_program <big_file`, su programa recibe un descriptor de archivo abierto al archivo real. Su programa, o en muchos casos las bibliotecas de E / S del lenguaje en el que se escribió, puede realizar diferentes acciones cuando se le presenta un descriptor de archivo que hace referencia a un archivo normal. Puede usar mmap (2) para asignar el archivo de entrada a su espacio de direcciones, en lugar de usar llamadas de sistema de lectura (2) explícitas. Estas diferencias podrían tener un efecto mucho mayor en sus resultados de referencia que el pequeño costo de ejecutar el binario `cat`.

Por supuesto, es un resultado de referencia interesante si el mismo programa tiene un rendimiento significativamente diferente entre los dos casos. Muestra que, de hecho, el programa o sus bibliotecas de E / S están haciendo algo interesante, como usar mmap (). Entonces, en la práctica, podría ser bueno ejecutar los puntos de referencia en ambas direcciones; tal vez descontando el resultado del 'gato' por un pequeño factor para "perdonar" el costo de ejecutar el "gato" en sí.





python if-statement keyword logical-operators and-operator