una - Diferencia entre ''y''(booleano) vs. ''&''(bitwise) en python. ¿Por qué diferencia en el comportamiento con listas vs matrices numpy?
funcion len python (7)
Acerca de la list
Primero, un punto muy importante, del cual todo seguirá (espero).
En Python ordinario, la list
no es especial de ninguna manera (excepto que tiene una linda sintaxis para construir, que es principalmente un accidente histórico). Una vez que se hace una lista [3,2,6]
, es para todos los efectos un objeto ordinario de Python, como un número 3
, un conjunto {3,7}
o una función lambda x: x+5
.
(Sí, admite el cambio de sus elementos, y es compatible con la iteración, y muchas otras cosas, pero eso es exactamente lo que es un tipo: admite algunas operaciones, mientras que no admite otras. Int soporta subir a una potencia, pero eso no hazlo muy especial, es solo lo que es una int. lambda admite llamadas, pero eso no lo hace muy especial, para eso es para lo que es lambda :).
Sobre and
and
no es un operador (puede llamarlo "operador", pero también puede llamar "a" un operador :). Los operadores en Python son (implementados a través de) métodos llamados a objetos de algún tipo, generalmente escritos como parte de ese tipo. No hay forma de que un método tenga una evaluación de algunos de sus operandos, pero puede (y debe) hacerlo.
La consecuencia de eso es que no se puede sobrecargar y no se puede sobrecargar. Es completamente general y se comunica a través de un protocolo específico. Lo que puedes hacer es personalizar tu parte del protocolo, pero eso no significa que puedas alterar completamente el comportamiento. El protocolo es:
Imagine Python interpretando "a y b" (esto no sucede literalmente de esta manera, pero ayuda a la comprensión). Cuando se trata de "y", mira el objeto que acaba de evaluar (a) y le pregunta: ¿es cierto? ( NO : ¿es True
?) Si usted es autor de una clase, puede personalizar esta respuesta. Si a
responde "no", and
(omite b completamente, no se evalúa en absoluto, y) dice: a
es mi resultado ( NO : falso es mi resultado).
Si a
no responde, and
pregunta: ¿cuál es su longitud? (De nuevo, puedes personalizar esto como autor de a
clase). Si a
responde 0, and
hace lo mismo que arriba, lo considera falso ( NO falso), omite b y da como resultado.
Si responde algo que no sea 0 a la segunda pregunta ("¿cuál es su longitud"), o no responde en absoluto, o responde "sí" al primero ("¿es cierto?"), and
evalúa b , y dice: b
es mi resultado. Tenga en cuenta que NO formula ninguna pregunta.
La otra forma de decir todo esto es que a and b
es casi lo mismo que b if a else a
, excepto a, se evalúa solo una vez.
Ahora siéntese unos minutos con un lápiz y papel, y convénzase de que cuando {a, b} es un subconjunto de {True, False}, funciona exactamente como se esperaría de los operadores booleanos. Pero espero haberte convencido de que es mucho más general, y como verás, mucho más útil de esta manera.
Poniendo esos dos juntos
Ahora espero que comprenda su ejemplo 1. and
no le importa si mylist1 es un número, lista, lambda o un objeto de una clase Argmhbl. Simplemente se preocupa por la respuesta de mylist1 a las preguntas del protocolo. Y, por supuesto, mylist1 responde 5 a la pregunta sobre la longitud, por lo que devuelve mylist2. Y eso es. No tiene nada que ver con los elementos de mylist1 y mylist2; no entran en ninguna parte de la imagen.
Segundo ejemplo: &
en la list
Por otro lado, &
es un operador como cualquier otro, como +
por ejemplo. Se puede definir para un tipo definiendo un método especial en esa clase. int
define como "y" a nivel de bit, y bool lo define como "y" lógico, pero esa es solo una opción: por ejemplo, los conjuntos y algunos otros objetos como las vistas de claves dict lo definen como una intersección de conjunto. list
simplemente no lo define, probablemente porque Guido no pensó en ninguna forma obvia de definirlo.
numpy
En la otra pierna: -D, las matrices numpy son especiales, o al menos están intentando serlo. Por supuesto, numpy.array es solo una clase, no puede anular and
de ninguna manera, por lo que hace la siguiente mejor opción: cuando se le pregunta "¿eres cierto?", Numpy.array levanta un ValueError, diciendo "por favor, reformula la pregunta, mi visión de la verdad no encaja en tu modelo ". (Tenga en cuenta que el mensaje ValueError no habla sobre and
- porque numpy.array no sabe quién le hace la pregunta, solo habla de la verdad).
Para &
, es una historia completamente diferente. numpy.array puede definirlo como lo desee, y define &
consistentemente con otros operadores: puntualmente. Así que finalmente obtienes lo que quieres.
HTH,
¿Qué explica la diferencia en el comportamiento de las operaciones booleanas y bit a bit en las listas frente a numpy.arrays?
Me confunde el uso apropiado de '' &
'' vs '' and
'' en python, ilustrado en los siguientes ejemplos simples.
mylist1 = [True, True, True, False, True]
mylist2 = [False, True, False, True, False]
>>> len(mylist1) == len(mylist2)
True
# ---- Example 1 ----
>>>mylist1 and mylist2
[False, True, False, True, False]
#I am confused: I would have expected [False, True, False, False, False]
# ---- Example 2 ----
>>>mylist1 & mylist2
*** TypeError: unsupported operand type(s) for &: ''list'' and ''list''
#I am confused: Why not just like example 1?
# ---- Example 3 ----
>>>import numpy as np
>>> np.array(mylist1) and np.array(mylist2)
*** ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
#I am confused: Why not just like Example 4?
# ---- Example 4 ----
>>> np.array(mylist1) & np.array(mylist2)
array([False, True, False, False, False], dtype=bool)
#This is the output I was expecting!
Esta answer y esta answer me ayudaron a entender que ''and'' es una operación booleana, pero ''&'' es una operación bit a bit.
Estaba reading cierta información para comprender mejor el concepto de reading , pero estoy luchando por usar esa información para dar sentido a mis 4 ejemplos anteriores.
Tenga en cuenta que, en mi situación particular, mi resultado deseado es una nueva lista donde:
len(newlist) == len(mylist1)
newlist[i] == (mylist1[i] and mylist2[i]) #for every element of newlist
El ejemplo 4, anterior, me llevó a la salida deseada, así que está bien.
Pero me siento confundido sobre cuándo / cómo / por qué debería usar ''y'' vs ''&''. ¿Por qué las listas y matrices numpy se comportan de manera diferente con estos operadores?
¿Alguien puede ayudarme a entender la diferencia entre las operaciones booleanas y bit a bit para explicar por qué manejan las listas y numpy.arrays de manera diferente?
Solo quiero asegurarme de continuar usando estas operaciones correctamente en el futuro. ¡Muchas gracias por la ayuda!
Numpy version 1.7.1
python 2.7
References all inline with text.
EDITS
1) Gracias @delnan por señalar que en mis ejemplos originales tenía una ambigüedad que estaba enmascarando mi confusión más profunda. He actualizado mis ejemplos para aclarar mi pregunta.
En Python, una expresión de
X and Y
devuelveY
, dado quebool(X) == True
o cualquiera deX
oY
evalúa como False, por ejemplo:True and 20 >>> 20 False and 20 >>> False 20 and [] >>> []
El operador bit a bit simplemente no está definido para las listas. Pero está definido para enteros: opera sobre la representación binaria de los números. Considere 16 (01000) y 31 (11111):
16 & 31 >>> 16
NumPy no es un psíquico, no sabe, si quiere decir que, por ejemplo,
[False, False]
debería ser igual aTrue
en una expresión lógica. En esto, anula un comportamiento estándar de Python, que es: "Cualquier colección vacía conlen(collection) == 0
esFalse
".Probablemente un comportamiento esperado de las matrices y el operador de NumPy.
Las operaciones con una lista de Python operan en la lista . list1 and list2
verificará si list1
está vacío, y devuelve list1
si es, y list2
si no lo está. list1 + list2
anexará list2
a list1
, por lo que obtendrá una nueva lista con elementos len(list1) + len(list2)
.
Los operadores que solo tienen sentido cuando se aplican a elementos, como &
, TypeError
un TypeError
, ya que las operaciones de elementos no son compatibles sin pasar por los elementos.
Las matrices Numpy admiten operaciones de elemento . array1 & array2
calcularán el bit a bit o para cada elemento correspondiente en array1
y array2
. array1 + array2
calculará la suma de cada elemento correspondiente en array1
y array2
.
Esto no funciona para and
y or
.
array1 and array2
es esencialmente una abreviatura para el siguiente código:
if bool(array1):
return array2
else:
return array1
Para esto necesitas una buena definición de bool(array1)
. Para operaciones globales como las usadas en las listas de Python, la definición es que bool(list) == True
si la list
no está vacía, y False
si está vacía. Para las operaciones numpy en cuanto a los elementos, existe cierta desajuste entre comprobar si algún elemento se evalúa como True
o si todos los elementos se evalúan como True
. Como ambos son discutiblemente correctos, Numpy no adivina y genera un ValueError
cuando bool()
se ValueError
(indirectamente) en una matriz.
Los operadores booleanos en cortocircuito ( and
, or
) no se pueden anular porque no hay una manera satisfactoria de hacerlo sin introducir nuevas funciones de lenguaje o sacrificar el cortocircuito. Como puede o no puede saber, evalúan el primer operando por su valor de verdad, y dependiendo de ese valor, evalúan y devuelven el segundo argumento, o no evalúan el segundo argumento y devuelven el primero:
something_true and x -> x
something_false and x -> something_false
something_true or x -> something_true
something_false or x -> x
Tenga en cuenta que se devuelve el (resultado de evaluar el) operando real, no el valor de verdad del mismo.
La única forma de personalizar su comportamiento es anular __nonzero__
(renombrado a __bool__
en Python 3), por lo que puede afectar qué operando se devuelve, pero no devolver algo diferente. Las listas (y otras colecciones) se definen como "verdaderas" cuando contienen algo y "falsey" cuando están vacías.
Los arreglos NumPy rechazan esa noción: para los casos de uso a los que apuntan, dos nociones diferentes de verdad son comunes: (1) Si cualquier elemento es verdadero, y (2) si todos los elementos son verdaderos. Dado que estos dos son completamente (y silenciosamente) incompatibles, y ninguno es claramente más correcto o más común, NumPy se niega a adivinar y requiere que use explícitamente .any()
o .all()
.
&
y |
(y not
, por cierto) puede ser anulado por completo, ya que no cortocircuitan. Pueden devolver cualquier cosa cuando se les reemplaza, y NumPy hace un buen uso de eso para hacer operaciones de elementos, como lo hacen con prácticamente cualquier otra operación escalar. Las listas, por otro lado, no transmiten operaciones a través de sus elementos. Así como mylist1 - mylist2
no significa nada y mylist1 + mylist2
significa algo completamente diferente, no hay un operador para las listas.
Para el primer ejemplo y base en el documento de django
Siempre devolverá la segunda lista, de hecho, una lista no vacía se ve como un valor verdadero para Python, por lo que Python devuelve el "último" valor verdadero para que la segunda lista
In [74]: mylist1 = [False]
In [75]: mylist2 = [False, True, False, True, False]
In [76]: mylist1 and mylist2
Out[76]: [False, True, False, True, False]
In [77]: mylist2 and mylist1
Out[77]: [False]
and
prueba si ambas expresiones son lógicamente True
mientras que &
(cuando se usa con valores True
/ False
) prueba si ambas son True
.
En Python, los objetos incorporados vacíos suelen tratarse como lógicamente False
mientras que los incorporados no vacíos son lógicamente True
. Esto facilita el caso de uso común en el que desea hacer algo si una lista está vacía y otra cosa si la lista no lo está. Tenga en cuenta que esto significa que la lista [False] es lógicamente True
:
>>> if [False]:
... print ''True''
...
True
Entonces, en el Ejemplo 1, la primera lista no está vacía y, por lo tanto, es lógicamente True
, por lo que el valor de verdad de and
es el mismo que el de la segunda lista. (En nuestro caso, la segunda lista no está vacía y, por lo tanto, es lógicamente True
, pero identificarla requeriría un paso de cálculo innecesario).
Por ejemplo, 2, las listas no se pueden combinar significativamente en una forma bit a bit porque pueden contener elementos arbitrarios a diferencia. Las cosas que se pueden combinar en bits incluyen: Trues y Falses, enteros.
Los objetos NumPy, por el contrario, admiten cálculos vectorizados. Es decir, te permiten realizar las mismas operaciones en múltiples piezas de datos.
El ejemplo 3 falla porque las matrices NumPy (de longitud> 1) no tienen ningún valor de verdad ya que esto evita la confusión de la lógica basada en vectores.
El ejemplo 4 es simplemente un bit and
operación vectorizados.
Línea de fondo
Si no está tratando con matrices y no está realizando manipulaciones matemáticas de enteros, probablemente desee
and
.Si tiene vectores de valores de verdad que desea combinar, use
numpy
con&
.
Ejemplo 1:
Así es como funciona el operador ''and'' .
x y y => si x es falso, luego x , else y
En otras palabras, dado que mylist1
no es False
, el resultado de la expresión es mylist2
. (Solo las listas vacías se evalúan como False
).
Ejemplo 2:
El operador &
es para un bit a bit y, como usted menciona. Las operaciones a nivel de bit solo funcionan en números. El resultado de a & b es un número compuesto por 1s en bits que son 1 en a y b . Por ejemplo:
>>> 3 & 1
1
Es más fácil ver lo que sucede con un literal binario (los mismos números que arriba):
>>> 0b0011 & 0b0001
0b0001
Las operaciones bit a bit son similares en concepto a las operaciones booleanas (verdad), pero funcionan solo en bits.
Entonces, dado un par de declaraciones sobre mi auto
- Mi coche es rojo
- Mi auto tiene ruedas
El "y" lógico de estas dos afirmaciones es:
(¿mi auto está rojo?) y (¿el coche tiene ruedas?) => lógico verdadero de falso valor
Ambas son ciertas, al menos para mi auto. Entonces el valor del enunciado como un todo es lógicamente verdadero.
El "y" bit a bit de estas dos afirmaciones es un poco más nebuloso:
(el valor numérico de la afirmación "mi automóvil es rojo") & (el valor numérico de la declaración "mi automóvil tiene ruedas") => número
Si python sabe cómo convertir los enunciados a valores numéricos, entonces lo hará y calculará el bit a bit y los dos valores. Esto puede llevarte a creer que &
es intercambiable con and
, pero como en el ejemplo anterior, son cosas diferentes. Además, para los objetos que no se pueden convertir, obtendrá un TypeError
.
Ejemplo 3 y 4:
Numpy implementa operaciones aritméticas para matrices:
Las operaciones aritméticas y de comparación en ndarrays se definen como operaciones de elementos, y generalmente dan como resultado resultados de objetos ndarray.
Pero no implementa operaciones lógicas para matrices, porque no puede sobrecargar operadores lógicos en Python . Es por eso que el ejemplo tres no funciona, pero el ejemplo cuatro sí.
Entonces para responder a su and
vs &
pregunta: Use and
.
Las operaciones en modo bit se utilizan para examinar la estructura de un número (qué bits se establecen, qué bits no se establecen). Este tipo de información se usa principalmente en interfaces de sistema operativo de bajo nivel ( bits de permisos de Unix , por ejemplo). La mayoría de los programas de Python no necesitarán saber eso.
Las operaciones lógicas ( and
, or
, not
), sin embargo, se usan todo el tiempo.