por qué se necesitan funciones vacías


9

Empecé a aprender Python y me pregunto por qué se necesitan funciones vacías en un lenguaje de programación

por ejemplo, en python:

def empty_func():
    pass

incluso en scripts de shell función vacía, las funciones vacías están disponibles.

Mi comprensión y pregunta:

  1. ¿Por qué el lenguaje de programación necesitaba funciones vacías? ¿Es solo para jugar con el lenguaje de programación o nada más que realmente importe?

  2. Si esto tiene un propósito, ¿alguien puede describir el caso de uso o dar un ejemplo real del uso de funciones vacías?

  3. ¿O hay alguna tradición de lenguajes de programación que permitan funciones vacías?


EDITAR (Cosas que obtuve al leer sus respuestas):

  • Para dibujar algoritmos o con funciones abstractas
  • Para enviar formularios sin necesidad de realizar ninguna acción
  • Marcador de posición para algunas operaciones obligatorias

1
pueden usarse como STUBS si la ejecución del programa espera encontrarlos / usarlos, sin embargo, no desea cambiar nada a través de ellos.
G.Rassovsky

Respuestas:


5

En los lenguajes de shell de la familia Bourne, el :comando, que no hace nada, se usa generalmente en dos situaciones:

  • Marcador de posición para cuando algo espera un comando obligatorio, p. Ej.

    while some_condtion
    do :
    done

    ya que dorequiere al menos un comando.

  • Descartar los argumentos, pero realizar efectos secundarios dentro de la lista de argumentos, p. Ej.

    : ${myvar=foo}

Estoy seguro de que probablemente haya otras aplicaciones que los expertos en shell conocerían :)

En Python (y otros idiomas) se usa con menos frecuencia. Puede actuar como un argumento para una función de orden superior cuando en realidad no desea hacer nada. Por ejemplo, supongamos que tiene una función que envía un formulario y permite que se llame a una función de forma asíncrona una vez que se completa el envío:

def submit(callback=empty_func):
    ...

De esta manera, si callbackno se proporciona, el envío seguirá adelante pero no se realizarán más acciones. Si lo hubiera utilizado Nonecomo valor predeterminado, tendría que verificar explícitamente si la devolución de llamada era None, agregando desorden al código.


1

Depende de dónde se encuentre en el ciclo de desarrollo, pero a veces al dibujar un algoritmo, desea hacer abstracciones sobre bloques complejos sin implementarlos de inmediato.

def full_algo():
  init_stuff()
  process_stuff()
  ...

Sabes cómo init_stufffuncionará, es bastante simple en tu cabeza, pero realmente no lo necesitas de inmediato, por lo que lo declaras como una función vacía. Permitirá que su código se compile y se ejecute sin preocuparse por los detalles sangrientos.

Otro uso para las aplicaciones lanzadas es cuando se usa la herencia. Suponga que tiene una clase grande que define el comportamiento del código específico de la plataforma. Puede terminar con una lógica similar a esta:

init_filesystem();
access_files();
release_filesystem();

Este código funcionará en muchas plataformas, pero algunas plataformas pueden no necesitar la inicialización del sistema de archivos. Entonces su herencia se verá así (virtual con = 0 en C ++ solo significa que las clases derivadas DEBEN implementar esos métodos):

class FileSystem{
  virtual void init_filesystem() = 0;
  virtual void access_files() = 0;
  virtual void release_filesystem() = 0;
};

Entonces, una implementación particular de esta clase (interfaz) podría no hacer nada para algunos de esos métodos. Alternativamente, la clase base podría declarar métodos vacíos para init / release en lugar de declararlos virtuales.

Finalmente (y vergonzosamente), a veces mantienes una aplicación muy antigua. Temes que eliminar métodos rompa las cosas. Esto sucede cuando tiene una herencia compleja que no se entiende correctamente o cuando tiene muchos punteros de función (devoluciones de llamada). Simplemente elimine el código dentro de ellos para que se les llame de todos modos sin romper nada.


0

Rufflewind hizo un buen trabajo cubriendo cuando podría usar una función vacía en un programa completado. En mi experiencia, tiende a usarse con más frecuencia en programas inacabados, por lo que puede planificar lo que va a escribir y aún compilarlo hasta que realmente lo implemente. En otras palabras, generalmente es solo un marcador de posición.

Es necesario en el caso de Python porque usa sangría para marcar bloques, a diferencia de los lenguajes tipo C que usan llaves {}. Esto significa que si no lo tenía pass, el analizador no podría decir si quería dejarlo vacío o si lo olvidó. La inclusión passhace que el analizador sea mucho más simple y le brinda una palabra conveniente para buscar cuando busca bloques no implementados.


1
Para el código inacabado, el lanzamiento NotImplementedErrores una solución más adecuada ya que "Los errores nunca deben pasar en silencio" y llamar a una función no implementada en un programa en vivo es un error.
ivan_pozdeev

Eso depende. Para el código que envía, sí. Pero si es un código que espera implementar en una hora y simplemente lo deja sin implementar mientras trabaja en las pruebas unitarias, simplemente no dejar ninguna implementación puede ser una mejor opción. A menudo, mi flujo de trabajo es 1) escribir el método de código auxiliar con pass 2) escribir la prueba de unidad que prueba el valor devuelto 3) verificar que la prueba falla (como el método devuelve indefinido) 4) implementar el método 5) verificar la prueba ahora pasa
Gort the Robot

0

Si bien no es algo que esperaría hacer en Python, hay momentos en el mundo de los controladores de dispositivos en los que necesita proporcionar una función vacía, para manejar un evento que (a) sabe que no sucederá o ( b) no me importa aunque lo haga.

También ve esto en C con devoluciones de llamada. Ocasionalmente, verá un código que ASUME que proporcionó una devolución de llamada e intentará llamarlo, ignorando el riesgo de un puntero nulo. Todo lo que puede hacer en ese caso es proporcionar una rutina de devolución de llamada vacía. (Sí, tengo un proveedor en particular en mente).


Usé passmucho como marcador de posición al escribir código, particularmente en las clases, cuando quiero que algo se pueda ejecutar antes de que todo esté completo. Es realmente el equivalente de {}Python, que Python no puede hacer ya que no usa llaves. En ese sentido, todos los idiomas que conozco permiten esto, es solo que solo un par como pythonrequiere una palabra clave. Incluso en los días de la asamblea que tuvimos NOP.
Gort the Robot

@StevenBurnap, generalmente cuando hago algo así, incluyo el equivalente local de printf (">>> rutina XXX llamada \ n");
John R. Strohm
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.