Python – Si no es una statement con 0.0

Tengo una pregunta con respecto a if not statement en Python 2.7 .

He escrito algún código y lo he usado if not declaraciones. En una parte del código que escribí, me refiero a una función que incluye una statement de if not saber para determinar si se ha ingresado una palabra clave opcional.

Funciona bien, excepto cuando 0.0 es el valor de la palabra clave. Entiendo que esto se debe a que 0 es una de las cosas que se considera “no”. Es probable que mi código sea demasiado largo para publicar, pero este es un ejemplo análogo (aunque simplificado):

 def square(x=None): if not x: print "you have not entered x" else: y=x**2 return y list=[1, 3, 0 ,9] output=[] for item in list: y=square(item) output.append(y) print output 

Sin embargo, en este caso me quedé con:

 you have not entered x [1, 9, None, 81] 

Donde me gustaría conseguir:

 [1, 9, 0, 81] 

En el ejemplo anterior, podría usar una lista de comprensión, pero suponiendo que quisiera usar la función y obtener la salida deseada, ¿cómo podría hacer esto?

Un pensamiento que tuve fue:

 def square(x=None): if not x and not str(x).isdigit(): print "you have not entered x" else: y=x**2 return y list=[1, 3, 0 ,9] output=[] for item in list: y=square(item) output.append(y) print output 

Esto funciona, pero parece una forma un tanto torpe de hacerlo. Si alguien tiene otra forma en que estaría bien, estaría muy agradecido.

Problema

Lo entiendes bien. not 0 (y not 0.0 ) devuelve True en Python . Se puede hacer una prueba simple para ver esto:

 a = not 0 print(a) Result: True 

Así, se explica el problema. Esta línea:

 if not x: 

Debe ser cambiado a otra cosa.


Soluciones

Hay algunas formas en que se puede hacer para solucionar el problema. Solo los voy a enumerar de la que creo que es la mejor solución hasta las últimas soluciones posibles:

  1. Para manejar todos los casos válidos posibles .

    Como el square debería esperar naturalmente un ingreso de números con la exclusión de un número complejo y debería return un error, de lo contrario, creo que la mejor solución es evaluar if not isinstance(x, numbers.Number) or isinstance(x, numbers.Complex):

     def square(x=None): if not isinstance(x, numbers.Number) or isinstance(x, numbers.Complex): # this sums up every number type, with the exclusion of complex number print ("you have not entered x") else: y=x**2 return y list=[1, 3, 0 ,9] output=[] for item in list: y=square(item) output.append(y) print (output) 

    Números. Número es la clase abstracta para verificar si el argumento x es un número (crédito a Copperfield por señalarlo).

    El extracto de la documentación de la biblioteca estándar de Python explica exactamente lo que necesita, con la excepción del número complejo:

    números de clase.número

    La raíz de la jerarquía numérica . Si solo quiere verificar si un argumento x es un número, sin importar qué tipo , use isinstance (x, Number) .

    Pero, no desea que la entrada sea un número complejo. Entonces, simplemente or isinstance(x, numbers.Complex) usando or isinstance(x, numbers.Complex)

    De esta manera, usted escribe la definition de square exactamente de la manera que lo desea. Esta solución, creo, es la mejor solución en virtud de su amplitud .

  1. Para manejar sólo los tipos de datos que desea manejar .

    Si tiene una lista de tipos de datos de inyección de datos válidos, también podría incluir solo los tipos de datos específicos que desea manejar. Es decir, no desea manejar los casos para tipos de datos que no sean los que ha especificado. Ejemplos:

     if not instance(x, int): #just handle int if not instance(x, (int, float)): #just handle int and float if not instance(x, (numbers.Integral, numbers.Rational)): #just handle integral and rational, not real or complex 

    Puede cambiar / extender la condición anterior fácilmente para diferentes tipos de datos que desea incluir o excluir, de acuerdo con su necesidad. Esta solución, creo, es la segunda mejor por la virtud de su personalización para su comprobación de validez .

    (El código de arriba se hace de una manera más pythonica , como lo sugiere el gato )

  1. No manejar casos imposibles: sabes lo que los usuarios no pondrían como entrada .

    Si sabe, piense que es más relajado, no los tipos de datos que desea manejar como en la segunda solución, sino los tipos de datos que el usuario no pondría, entonces puede tener una verificación de condición más flexible como esta:

     if not isinstance(x, numbers.Number): # this is ok, because the user would not put up complex number 

    Esta solución, creo, es la tercera mejor por la virtud de ser una de las comprobaciones más simples y potentes .

    El único inconveniente de esta solución es que no maneja tipos complejos. Por lo tanto, solo se puede implementar debido a que los usuarios no tendrían un número complejo como entrada.

  1. Para manejar errores de entrada solo para las entradas posibles conocidas que pueden causar los errores .

    Por ejemplo, si sabe que x siempre es int o None , y por lo tanto, el único error de entrada posible es None , simplemente podemos escribir la lógica para evitar que y se evalúe solo cuando x es None esta manera:

     def square(x=None): if x is None: print ("you have not entered x") else: y=x**2 return y list=[1, 3, 0 ,9] output=[] for item in list: y=square(item) output.append(y) print (output) 

    Esta solución tiene la virtud de ser la más sencilla .

    … y, sin embargo, el más peligroso para ser usado si no sabe exactamente lo que los usuarios pondrían para la entrada. De lo contrario, esta solución está bien y también es la más sencilla.

    Su solución, creo que más o menos pertenece a esta categoría. Usted sabe qué entrada dará el usuario y qué no lo hará. Por lo tanto, utilizando esta solución o su propia solución:

     if not x and not str(x).isdigit(): 

    Está bien, excepto que la solución del ejemplo es más simple.


Dado su caso, puede utilizar cualquier solución anterior para obtener:

  [1, 9, 0, 81] 

(Nota al margen: Intento dar formato a las soluciones para que parezcan “soluciones canónicas” para facilitar la lectura. De esta manera, aquellos que tienen las mismas preguntas y que visitan esta página en el futuro pueden encontrar soluciones más completas y legible)

Ya que está utilizando None para indicar “este parámetro no está establecido”, eso es exactamente lo que debe verificar al usar la palabra clave is :

 def square(x=None): if x is None: print "you have not entered x" else: y=x**2 return y 

Verificar el tipo es engorroso y propenso a errores, ya que tendría que verificar todos los tipos de entrada posibles , no solo int .

 if x is None: print 'x is None' 

Por lo que yo entiendo, desea detectar los casos en los que no se proporcionó ninguna entrada:

 if x is None: ... 

Y los casos donde no es un número. Con el segundo acabarás teniendo algunos problemas, porque tal vez quieras permitir un número de ndarrays en el futuro o alguna otra cosa, normalmente te sugiero que no se moleste en excluir otras clases, pero si solo quieres permitir int y float luego usar

 if isinstance(x, (int, float, ...)): ... 

los ... representan otras clases permitidas (tal vez Decimal o Fractions ).

Para que puedas escribirlo como:

 if x is not None and isinstance(x, (int, float)): return x**2 else: print "you have not entered x" 

Como None no es un int ni un float , también puede omitir la primera condición y escribir:

 if isinstance(x, (int, float)): ... 

Si puede identificar un solo tipo con el que todas las entradas deben ser compatibles , entonces puede convertirlo y manejar la excepción:

 def square(x=None): try: return float(x)**2 except TypeError: print "You did not enter a real number" return None # Explicit is better than implicit 

Esto tiene algunas ventajas.

  • Implica que todo lo que el usuario te envíe es compatible con float . Puede ser cualquier número, una cadena que contenga un número ( '5.0' ) o cualquier otra cosa que se pueda convertir en un float . (Las instancias float se devuelven sin cambios.)
  • Es sencillo. No hay magia extraña en tu método. No estás rompiendo el pato escribiendo. Solo estás haciendo cumplir tus requisitos para hacer que la cosa funcione bien.
  • No es vulnerable a las trampas involucradas con la verificación del tipo. Las personas que llaman pueden decirle cómo su tipo personalizado se convierte en float . Python proporciona el método mágico __float__ , por lo que si sus usuarios tienen tipos exóticos y necesitan usar su función, no se hundirán.
  • Es idiomático. Los progtwigdores experimentados de Python esperarán este tipo de código; sigue el principio de “más fácil pedir perdón que permiso”.

Un lado ( tal vez ):

Si None es un valor no válido, no lo convierta en un valor predeterminado. Solo obliga a la persona que llama a proporcionar entrada:

 def square(x): try: return float(x)**2 except TypeError: print "You did not enter a real number" return None 

U puede manejar la excepción aquí. Hacer codigo asi

 def square(x): if not x: print "you have not entered x" else: try: int(y)=x**2 return y except TypeError: pass list=[1, 3, 0 ,9] output=[]