[vc_row][vc_column][vc_column_text]Cuando se escriben las funciones, los programadores de Python obtienen un significado especial para el valor de retorno de None. Parece tener sentido en algunos casos. Por ejemplo, supongamos que quieres una función auxiliar que divide un número entre otro. En el caso de dividir por cero, devolver None parece natural por que el resultado no esta definido.
1 2 3 4 5 | def divide(a, b): try: return a / b except ZeroDivisionError: return None |
El código para el uso de la función puede ser de acuerdo a:
1 2 3 | result = divide(x, y) if result is None: print('Invalid inputs') |
¿Que pasa si el numerador es cero? Esto causa que el valor de retorno sea cero ( si el denominador es diferente de cero). Esto puede causar el problema si evalúas la condición en una sentencia if. En forma accidental puedes buscar por un equivalente False para indicar el error en lugar de buscar por None.
1 2 3 4 | x, y = 0, 5 result = divide(x, y) if not result: print('Invalid inputs') # Esto está mal |
Este es un error común en el código de Python cuando None tiene un significado específico especial. Esta es la razón por la cual devolver None desde una función es propenso a errores. Hay dos formas de reducir la posibilidad de tales errores.
La primera forma es dividir el valor de retorno en dos tuplas. La primera parte de la tupla indica que la operación fue un éxito o una falla. La segunda parte es el resultado real que se calculó.
1 2 3 4 5 | def divide(a, b): try: return True, a / b except ZeroDivisionError: return False, None |
Los que utilicen la función tienen que interpretar la tupla. Eso los obliga a considerar el estado de la tupla en lugar de solo mirar el resultado de la división.
1 2 3 | success, result = divide(x, y) if not success: print('Invalid inputs') |
El problema es que los que utilicen la función pueden ignorar fácilmente la primera parte de la tupla. El código resultante no se ve mal a primera vista. Esto es tan malo como simplemente devolver None.
1 2 3 | _, result = divide(x, y) if not result: print('Invalid inputs') |
La segunda y mejor forma de reducir estos errores es nunca devolver None en absoluto.En su lugar, haga una excepción de retorno y haga que se maneje. Aquí, se convierte un ZeroDivisionError en un ValueError para indicarle a la persona que los valores de entrada son malos:
1 2 3 4 5 | def divide(a, b): try: return a / b except ZeroDivisionError as e: raise ValueError('Invalid inputs') from e |
Ahora los que llaman a la función deben manejar la excepción para el caso de un ingreso invalido. Ahora ya no se requiere una condición en el valor de retorno de la función. Si la función no generó una excepción, entonces el valor de retorno debe ser bueno. El resultado del manejo de excepciones es claro.
1 2 3 4 5 6 7 | x, y = 5, 2 try: result = divide(x, y) except ValueError: print('Invalid inputs') else: print('Result is %.1f' % result) |
[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]
Puntos a recordar
- Las funciones de imagen que devuelven None para indicar un significado especial son propensas a errores porque None y otros valores (por ejemplo, cero, la cadena vacía) todas evalúan False en las sentencias condicionales.
- La excepciones Image Raise para indicar situaciones especiales en lugar de devolver None. Espere que el código de llamada maneje adecuadamente las excepciones cuando estén documentadas.
Este artículo se encuentra basado en el libro Effective Python: 59 Specific Ways to Write Better Python by Brett Slatkin[/vc_column_text][/vc_column][/vc_row]