2010-08-15 12 views
22

The Zen of Python dice" Explicit is better than implicit ". Sin embargo, la forma "Pythonic" para comprobar si está utilizando el vacío booleaness implícita:¿Por qué no hay una comprobación de vacío explícita (por ejemplo, `está vacío`) en Python

if not some_sequence: 
    some_sequence.fill_sequence() 

Esto será cierto si some_sequence es una secuencia vacía, pero también si es None o 0.

Comparar con un cheque vacío explícita teórico:

if some_sequence is Empty: 
    some_sequence.fill_sequence() 

Con un poco de nombre de variable desfavorablemente elegido el booleaness implícita para comprobar si el vacío se vuelve aún más confuso:

if saved: 
    mess_up() 

Comparar con:

if saved is not Empty: 
    mess_up() 

Véase también: "Python: What is the best way to check if a list is empty?". Me parece irónico que la respuesta más votada afirme que implícita es pitonica.

¿Hay una razón más alta por la que no hay una comprobación de vacío explícita, como por ejemplo is Empty en Python?

+0

'guardado! = []' Y 'guardado == []' funcionan bien. ¿Cómo son esos controles de vacío no explícitos? ¿Acabas de decir que 'is' es más estricto que' == '? –

Respuesta

14

La razón por la que no hay is Empty es sorprendentemente simple una vez usted entiende lo que hace el operador is.

Desde el python manual:

los operadores is y is not prueba de la identidad del objeto: x is y es cierto si y sólo si x y y son el mismo objeto. x is not y produce el valor de verdad inversa .

Eso significa some_sequence is Empty comprueba si some_sequence es el mismo objeto que Empty. Eso no puede funcionar de la manera que sugeriste.

Consideremos el siguiente ejemplo:

>>> a = [] 
>>> b = {} 

Ahora vamos a suponer que hay esta is Empty construcción en Python:

>>> a is Empty 
True 
>>> b is Empty 
True 

Pero dado que el operador is hace control de identidad que significa que a y b son idénticos a Empty. Que a su vez debe significar que a y b son idénticos, pero no lo son:

>>> a is b 
False 

Así que para responder a su pregunta "¿por qué no hay is Empty en Python?": Porque is hace control de identidad.

el fin de tener el constructo is Empty que debe o piratear el operador is para significar otra cosa o crear algún Empty objeto mágico que de alguna manera detecta colecciones vacías y luego ser idénticos a ellos.

En lugar de preguntar por qué no hay is Empty debe preguntar por qué no hay una función integrada isempty() que llame al método especial __isempty__().

Así que en lugar de utilizar booleaness implícita:

if saved: 
    mess_up() 

tenemos explícita de verificación vacía:

if not isempty(saved): 
    mess_up() 

donde la clase de saved tiene un método implementado __isempty__() a cierta lógica cuerdo.

Creo que es mucho mejor que usar Booleaness implícita para comprobar el vacío.

Por supuesto se puede definir fácilmente su propia función isempty():

def isempty(collection): 
    try: 
    return collection.__isempty__() 
    except AttributeError: 
    # fall back to implicit booleaness but check for common pitfalls 
    if collection is None: 
     raise TypeError('None cannot be empty') 
    if collection is False: 
     raise TypeError('False cannot be empty') 
    if collection == 0: 
     raise TypeError('0 cannot be empty') 
    return bool(collection) 

y luego definir un método __isempty__() que devuelve un valor lógico para todas las clases de colección.

+0

http://bugs.python.org/issue17921 – lesmana

22

polimorfismo en if foo: y if not foo: no es una violación de "implícita vs explícita": se explícitamente delegados al objeto que está siendo verificado la tarea de saber si es verdadera o falsa. Lo que eso significa (y la mejor manera de verificarlo) obviamente depende y debe depender del tipo del objeto, por lo que la guía de estilo ordena a la delegación: tener un código de nivel de aplicación arrogantemente afirma que sabe mejor que el objeto sería el colmo de la locura.

Por otra parte, X is Whatever siempre, invariablemente significa que X es exactamente el mismo objeto como Whatever. Hacer una excepción totalmente única para Empty o cualquier otro valor específico de Whatever sería absurdo, es difícil imaginar un enfoque más no protónico. Y "ser exactamente el mismo objeto" es obviamente transitivo, por lo que nunca más podrías tener listas vacías distintas, conjuntos vacíos, dictados vacíos ... felicidades, acabas de diseñar un lenguaje totalmente inútil e inútil, donde cada contenedor vacío "se derrumba" alocadamente en un solo objeto contenedor vacío (imagínese la diversión cuando alguien intenta mutar un contenedor vacío ...?!).

+8

¡Pero la verdad y el vacío son conceptos completamente diferentes! Está bien decir que la delegación de la veracidad al objeto tiene sentido ** si y solo si ** hay un valor booleano claro encapsulado por el objeto. Para el caso de las secuencias/matrices, ¿por qué la equivalencia de vacío a verdadero es mejor que la equivalencia de "todos los elementos son verdaderos" a la verdad? Estoy de acuerdo con el OP; parece confuso e implícito entender que las secuencias son falsas si están vacías ... –

+0

Este es un patrimonio de C donde falso era equivalente a 0 y a! = 0 significaba que a es cierto. Entonces, en python la veracidad significa "tener algún valor significativo" y este significado tiene un amplio uso. – Odomontois

+1

@Odomontois Me inclinaría más a decir que desciende de lisp donde '()', el conjunto vacío, se toma como la __definición__ de booleano falso. – aaronasterling

5

Acepto que a veces if foo: no es explícito para mí cuando realmente quiero decirle al lector del código que es vacío que estoy probando. En esos casos, uso if len(foo):. Suficientemente explícito

Estoy 100% de acuerdo con Alex w.r.t is Empty siendo antiponético.

+4

Con la misma lógica, 'if len (foo):' se basa en el hecho de que 0 es implícitamente falso ;-p Tiene que comenzar con convención * en algún lugar *. –

+6

Nunca haga esto; está forzando al contenedor a calcular la longitud, lo que puede ser costoso para algunas estructuras de datos, cuando todo lo que desea saber es si está vacío. –

+4

@Glenn Maynard: "Nunca" es una palabra bastante fuerte. 1. La mayoría de las veces, son listas con las que estamos trabajando. 2. La optimización prematura es la raíz de todo mal. 3. La legibilidad cuenta. –

0

Considere que Lisp ha estado usando() lista vacía o su símbolo NIL bastantes años como Falso y T o cualquier cosa no NIL como Verdadero, pero generalmente el cálculo de Verdad ya produjo algunos resultados útiles que no necesitan reproducirse si es necesario. Mire también el método de partición de cadenas, donde el resultado intermedio funciona muy bien, mientras que el control con el no vacío es la convención True.

Trato en general de evitar el uso de len, ya que es la mayoría de las veces muy costoso en circuitos cerrados. A menudo vale la pena actualizar el valor de longitud del resultado en la lógica del programa en lugar de volver a calcular la longitud.

Para mí preferiría que Python tuviera False as() o [] en lugar de 0, pero así es como es. Entonces sería más natural usar no [] como no vacío. Pero ahora() no es [] es verdadera lo que podría utilizar:

emptyset = set([])  
if myset == emptyset: 

Si quieres ser explícita del caso conjunto vacío (no MYSET se establece ([]))

yo mismo bastante como el si no es myset como mi comentarista.

Ahora me vino a la mente que tal vez esta es la más cercana a not_empty explícita:

if any(x in myset for x in myset): print "set is not empty" 

y así está vacía sería:

if not any(x in myset for x in myset): print "set is empty" 
+0

'if not myset' es lo suficientemente explícito. – aaronasterling

+0

no relacionado con la pregunta inicial, pero ¿tiene ejemplos de "a menudo vale la pena actualizar el valor de longitud del resultado en la lógica del programa en lugar de volver a calcular la longitud"? ¿Se trata de colecciones integradas? – Odomontois

+0

En mi programa de anagrama podría acelerar el chequeo de posible anagrama al no usar len pero dejar que la función contains devuelva no solo las letras restantes si string contiene letras del otro, sino también la longitud de las letras restantes. Tal vez misgeneralized, pero el perfil mostró una parte considerable gastada en funciones len antes de la optimización. El tipo de datos era una cadena, por lo que es una secuencia inmutable. Tal vez debería editar a menudo en mi declaración como 'a veces'. No creo que len sea O (1) operación para ningún tipo de secuencia. –

0

Hay es una comprobación de vacío explícita para iterables en Python. Se deletrea not. ¿Qué hay implícito allí? not da True cuando iterable está vacío, y da False cuando no está vacío.

¿A qué se opone exactamente? ¿Un nombre? Como otros te han dicho, sin duda es mejor que is Empty. Y no es tan poco gramatical: teniendo en cuenta que las cosas se suelen nombrar en Python, podemos imaginar una secuencia llamada widgets, que contiene, sorprendentemente, algunos widgets. Luego,

if not widgets: 

se puede leer como "si no hay widgets ...".

¿O le molesta la longitud? Explícito no significa detallado, esos son dos conceptos diferentes. Python no tiene el método addition, tiene el operador +, que es completamente explícito si conoce el tipo al que lo está aplicando. Lo mismo con not.

Cuestiones relacionadas