Next Up Previous Hi Index

Chapter 3

Funciones

3.1 Llamadas a funciones

Ya hemos visto un ejemplo de una llamada a una función:

  >>> type("32")
  <type 'string'>

El nombre de la función es \texttt{type, y muestra el tipo de un valor o de una variable. El valor o variable, llamado el \textbf{argumento} de la función, ha de estar encerrado entre paréntesis. Es habitual decir que una función ``toma'' un argumento y ``devuelve'' un resultado. El resultado se llama \textbf{valor de retorno}. \index{argumento} \index{valor de retorno} En lugar de imprimir el valor de retorno, podemos asignárselo a una variable. \begin{verbatim} >>> nereida = type("32") >>> print nereida \end{verbatim} Otro ejemplo más: la función \texttt{id} toma como argumento un valor o una variable y devuelve un entero que actúa como identificador único de ese valor. \begin{verbatim} >>> id(3) 134882108 >>> yanira = 3 >>> id(yanira) 134882108 \end{verbatim} Cada valor tiene un \texttt{id}, que es un valor único relacionado con dónde se almacena en la memoria del computador. El \texttt{id} de una variable es el \texttt{id} del valor al que hace referencia. \section{Conversión de tipos} \index{conversión de tipos} \index{tipos!conversión} Python proporciona una colección de funciones internas que convierten valores de un tipo a otro. La función \texttt{int} toma un valor y lo convierte a un entero, si es posible, o da un error si no es posible. \begin{verbatim} >>> int("32") 32 >>> int("Hola") ValueError: invalid literal for int(): Hola \end{verbatim} \texttt{int} también convierte valores de coma flotante a enteros, pero recuerde que siempre redondea hacia abajo: \begin{verbatim} >>> int(3.99999) 3 \end{verbatim} La función \texttt{float} que convierte enteros y cadenas en números en coma flotante: \begin{verbatim} >>> float(32) 32.0 >>> float("3.14159") 3.14159 \end{verbatim} Finalmente, está la función \texttt{str}, que convierte a tipo \texttt{string}: \begin{verbatim} >>> str(32) '32' >>> str(3.14149) '3.14149' \end{verbatim} Pudiera parecer extraño que Python distinga entre el valor entero \texttt{1} y el valor de coma flotante \texttt{1.0}. Tal vez representen el mismo número, pero pertenecen a tipos distintos. El motivo es que se representan de forma distinta dentro del computador. \section{Coerción de tipos} \index{coerción de tipos} \index{tipos!coerción} \index{división de enteros} \index{enteros!división} Ahora que ya sabemos convertir entre tipos, tenemos otra forma de enfrentarnos a la división de enteros. Volviendo al ejemplo del capítulo anterior, suponga que queremos calcular qué fracción de una hora había transcurrido. La expresión más obvia, \texttt{minuto / 60}, realiza una división de enteros, por lo que el resultado es siempre 0, incluso 59 minutos después de la hora. Una alternativa es convetir \texttt{minuto} a tipo float (coma flotante) y luego efectuar una división de coma flotante: \begin{verbatim} >>> minuto = 59 >>> float(minuto) / 60.0 0.983333333333 \end{verbatim} O bien podemos sacar provecho de las reglas de la conversión automática de tipos, llamada \textbf{coerción} de tipos. Para los operadores matemáticos, si uno de los operandos matemáticos es tipo \texttt{float}, el otro se convierte automáticamente en \texttt{float}. \index{coercion} \begin{verbatim} >>> minuto = 59 >>> minuto / 60.0 0.983333333333 \end{verbatim} Al usar un denomidador que es \texttt{float}, obligamos a Python a hacer división de coma flotante. \section{Funciones matemáticas} \index{funciones matemáticas} \index{matemáticas!funciones} Es posible que ya haya visto usted en matemáticas funciones como \texttt{sin} (seno) y \texttt{log}, y que haya aprendido a evaluar expresiones como \texttt{sin(pi/2)} y \texttt{log(1/x)}. Primero evalúa la expresión entre paréntesis, (el argumento). Por ejemplo, \texttt{pi/2} es aproximadamente 1.571, y \texttt{1/x} es 0.1 (si \texttt{x} es igual a \texttt{10.0}). Luego evalúa la función en sí misma, bien mirándola en una tabla, bien llevando a cabo diversos cálculos. El \texttt{sin} (seno) de 1.571 es 1, y el \texttt{log} de 0.1 es -1 (suponiendo que \texttt{log} indique el logaritmo de base 10). Este proceso puede aplicarse repetidamente para evaluar expresiones más complicadas como \texttt{log(1/sin(pi/2))}. Primero evaluamos el argumento de la función más interna, luego se evalúa la función, y así sucesivamente. Python dispone de un módulo matemático que proporciona la mayoría de las funciones matemáticas habituales. Un \textbf{módulo} es un archivo que contiene una colección de funciones agrupadas juntas. \index{módulo} Antes de poder usar las funciones de un módulo, tenemos que importarlo: \begin{verbatim} >>>import math \end{verbatim} Para llamar a una de las funciones, tenemos que especificar el nombre del módulo y el nombre de la función, separados por un punto. A esto se le llama notación de punto: \begin{verbatim} decibelio = math.log10 (17.0) angulo = 1.5 altura = math.sin(angulo) \end{verbatim} La primera sentencia da a \texttt{decibelio} el valor del logaritmo de 17, en base \texttt{10}. Hay también una función llamada \texttt{log} que toma logaritmos en base \texttt{e}. La tercera sentencia halla el seno del valor de la variable \texttt{angulo}. \texttt{sin} y las otras funciones trigonométricas (\texttt{cos}, \texttt{tan}, etc.) toman sus argumentos en \emph{radianes}. Para convertir de grados a radianes, puede dividir por 360 y multiplicar por \texttt{2{*}pi}. Por ejemplo, para hallar el seno de 45 grados, calcule primero el ángulo en radianes y luego halle el seno: \begin{verbatim} grados = 45 angulo = grados * 2 * math.pi / 360.0 math.sin(angulo) \end{verbatim} La constante \texttt{pi} también es parte del módulo \texttt{math}. Si se sabe la geometría, puede verificar el resultado comparándolo con el de la raíz cuadrada de 2, dividida entre 2. \begin{verbatim} >>> math.sqrt(2) / 2.0 0.707106781187 \end{verbatim} \section{Composición} \index{composición} \index{funciones!composición} Igual que con las funciones matemáticas, las funciones de Python se pueden componer; eso quiere decir que se usa una expresión como parte de otra. Por ejemplo, puede usar cualquier expresión como argumento de una función: \begin{verbatim} x = math.cos(angulo + pi/2) \end{verbatim} Esta sentencia toma el valor de \texttt{pi}, lo divide entre dos y le añade el resultado al valor de \texttt{angulo}. La suma se pasa luego como argumento a la función \texttt{cos}. También puede tomar el resultado de una función y pasárselo como argumento a otra: \begin{verbatim} x = math.exp(math.log(10.0)) \end{verbatim} Esta sentencia encuentra el logaritmo en base \texttt{e} de 10 y luego eleva \texttt{e} a ese exponente. El resultado queda asignado a \texttt{x}. \section{Añadir funciones nuevas} Hasta ahora sólo hemos usado las funciones que vienen incluidas con Python, pero también es posible añadir nuevas funciones. La creación de nuevas funciones para resolver sus problemas partigulares es una de las cosas más útiles de los lenguajes de programación de propósito general. En contextos de programación, \textbf{función} es una secuencia de instrucciones con nombre, que lleva a cabo la operación deseada. Esta operación se especifica en una \textbf{definición de función}. Las funciones que hemos usado hsta ahora las han definido por nosotros, y esas definiciones están ocultas. Eso es bueno, ya que nos permite usar funciones sin preocuparnos sobre los detalles de sus definiciones. \index{función} \index{definición de función} \index{función!definición} La sintaxis de la definición de una función es: \begin{verbatim} def NOMBRE( LISTA DE PARAMETROS ): SENTENCIAS \end{verbatim} Puede inventarse el nombre que desee para su función, con la excepción de que no puede usar las palabras reservadas de Python. La lista de parámetros especifica qué información, en caso de haberla, ha de proporcionar para usar la función nueva. Puede haber cualquier número de sentencias dentro de la función, pero tienen que estar indentadas desde el margen izquierdo. En los ejemplos de este libro se usará una indentación de dos espacios. El primer par de funciones que escribiremos no tienen parámetros, de manera que su sintaxis es: \begin{verbatim} def nueva_linea(): print \end{verbatim} Esta función se llama \texttt{nueva\_linea}. Los paréntesis vacíos indican que no tiene parámetros. Contiene una única sentencia, que muestra como salida un carácter de nueva línea (es lo que sucede cuando utiliza una orden \texttt{print} sin argumentos). Llamamos entonces a la función nueva usando la misma sintaxis que usamos para las funciones internas: \begin{verbatim} print "Primera linea." nueva_linea() print "Segunda linea." \end{verbatim} The output of this program is \begin{verbatim} Primera linea. Segunda linea. \end{verbatim} Observe el espacio añadido que hay entre las dos líneas. Si quisiéramos más espacios, entre las líneas, ¿qué haríamos? Podemos llamar varias veces a la misma función: \begin{verbatim} print "Primera linea." nueva_linea() nueva_linea() nueva_linea() print "Segunda linea." \end{verbatim} O bien podemos escribir una nueva función que llamaremos \texttt{tresLineas}, y que imprima tres nuevas líneas: \begin{verbatim} def tresLineas(): nueva_linea() nueva_linea() nueva_linea() print "Primera Linea." tresLineas() print "Segunda Linea." \end{verbatim} Esta función contiene tres sentencias, las cuales están todas indentadas con dos espacios. Puesto que la siguiente sentencia no está indentada, Python sabe que no es parte de la función. Observe los siguientes puntos con respecto a este programa: \begin{enumerate} \item Se puede llamar al mismo procedimiento repetidamente. De hecho es bastante útil hacerlo, además de habitual. \item Se puede llamar a una función desde dentro de otra función: en este caso \texttt{tresLineas} llama a \texttt{nueva\_linea}. \end{enumerate} Hasta ahora puede no haber quedar claro por qué vale la pena crear todas estas funciones nuevas. En realidad hay muchísimas razones, pero este ejemplo demuestra dos: \begin{itemize} \item Crear una nueva función le da la oportunidad de dar un nombre a un grupo de sentencias. Las funciones simplifican su programa al ocultar cálculos complejos detrás de órdenes sencillas, y usar palabras de su propia lengua en vez de código arcano. \item Crear una nueva función hace que el programa sea más pequeño, al eliminar código repetitivo. Por ejemplo, una manera de imprimir nueve líneas consecutivas es llamar a \texttt{tresLineas} tres veces. \end{itemize} \begin{quote} \emph{Como actividad, escriba una función llamada} \texttt{\emph{nueveLineas}} \emph{que use} \texttt{\emph{tresLineas}} \emph{para imprimir nueve líneas en blanco. ¿Cómo imprimiría 27 líneas nuevas?} \end{quote} \section{Las definiciones y el uso} Juntando los fragmentos de código de la sección anterior, el programa completo queda de la siguiente manera: \begin{verbatim} def nueva_linea(): print def tresLineas(): nueva_linea() nueva_linea() nueva_linea() print "Primera Linea." tresLineas() print "Segunda Linea." \end{verbatim} El presente programa contiene dos definiciones de funciones: \texttt{nueva\_linea} y \texttt{tresLineas}. Las definiciones de funciones se ejecutan como el resto de sentencias, pero el efecto es crear una nueva función. Las sentencias del interior de la función no se ejecutan hasta que se llama a la función, y la definición de la función no genera salida. Como era de esperar, tiene que crear una función antes de poder ejecutarla. En otras palabras, la definición de la función tiene que ejecutarse antes de la primera vez que se la invoque. \begin{quote} \emph{Como actividad, pruebe a ejecutar este programa moviendo las tres últimas sentencias al principio del programa. Registre qué mensaje de error obtiene usted.} \emph{Como segunda actividad, pruebe a tomar la versión del programa que funcionaba y a mover la definción de} \texttt{\emph{nueva\_linea}} \emph{más abajo que la definición de} \texttt{\emph{tresLineas}}\emph{. ¿Qué ocurre cuando ejecuta el programa?} \end{quote} \section{Flujo de ejecución} \index{flujo de ejecución} Para asegurarse de que una función se define antes de su primer uso, tiene que conocer el orden en el que se ejecutan las sentencias; a esto se le llama \textbf{flujo de ejecución}. La ejecución comienza siempre por la primera sentencia del programa. Las sentencias se ejecutan a razón de una cada vez, en orden, hasta que se alcanza una llamada a una función. Las definiciones de funciones no alteran el flujo de ejecución del programa, pero recuerde que las sentencias que hay dentro de la función no se ejecutan hasta que se hace la llamada a la función. Aunque no es habitual, puede definir una función dentro de otra. En este caso, la definición de función interior no se ejecuta hasta que no se llama a la función exterior. Las llamadas a funciones son como un desvío en el flujo de ejecución. En lugar de ir a la siguiente sentencia, el flujo salta hasta la primera línea de la función a la que se llama, ejecuta todas las sentencias que encuentre allí, y vuelve a retomar la ejecución en el punto donde lo dejó. Esto suena bastante sencillo... hasta que se acuerda de que una función puede llamar a otra. Mientras estamos en medio de una función, podríamos vernos obligados a abandonarla e ir a ejecutar sentencias en otra función más. Pero mientras estamos en esta nueva función, ¡podríamos salirnos y ejecutar otra función más! Afortunadamente, a Python se le da bien tomar nota de dónde está, de manera que cada vez que se completa una función, el programa retoma el punto en donde lo dejó en la función que hizo la llamada. Cuando llega al final del programa, termina. ¿Cuál es la moraleja de toda esta historia? Cuando esté leyendo un programa, no lo lea desde la parte superior a la inferior. En lugar de eso, siga el flujo de ejecución. \section{Parámetros y argumentos} \label{parameters} \index{par'ametros} \index{funciones!par'ametros} \index{argumentos} \index{funciones!argumentos} Algunas de las funciones internas que hemos usado precisan de argumentos, los valores que controlan cómo la función lleva a cabo su tarea. Por ejemplo, si desea encontrar el seno de un número, tiene que indicar de qué número se trata. Así pues, \texttt{sin} toma como argumento un valor numérico. Algunas funciones toman más de un argumento, como \texttt{pow}, que toma dos argumentos: la base y el exponente. Dentro de la función, los valores que se le han pasado se asignan a variables llamadas \textbf{parámetros}. He aquí un ejemplo de una función definida por el usuario, que toma un parámetro: \begin{verbatim} def imprimeDoble(paso): print paso, paso \end{verbatim} Esta función toma un único argumento y se lo asigna a un parámetro llamado \texttt{paso}. El valor del parámetro (en este punto todavía no tenemos ni idea de cuál será) se imprime dos veces, seguido por un carácter de nueva línea. El nombre \texttt{paso} se eligió para sugerir que el nombre que le dé a un parámetro depende de usted, pero en general es mejor que elija un nombre más ilustrativo que \texttt{paso}. La función \texttt{imprimeDoble} sirve con cualquier tipo (de dato) que se pueda imprimir: \begin{verbatim} >>> imprimeDoble('Jamón') Jamón Jamón >>> imprimeDoble(5) 5 5 >>> imprimeDoble(3.14159) 3.14159 3.14159 \end{verbatim} En la primera llamada a la función, el argumento es una cadena; en la segunda es un entero, y en la tercera es un número de coma flotante. Las mismas reglas de composición que se aplican a las funciones internas se aplican también a las funciones definidas por el usuario, así que puede usar cualquier tipo de expresión como argumento de \texttt{imprimeDoble}. \begin{verbatim} >>> imprimeDoble('Jamón'*4) JamónJamónJamónJamón JamónJamónJamónJamón >>> imprimeDoble(math.cos(math.pi)) -1.0 -1.0 \end{verbatim} Como de costumbre, se evalúa la expresión antes de ejecutar la función, de modo que \texttt{imprimeDoble} devuelve \texttt{JamónJamónJamónJamón JamónJamónJamónJamón} en lugar de \texttt{'Jamón'*4' Jamón'*4}. Asimismo podemos usar una variable como argumento: \begin{verbatim} >>> latoya = 'Dafne, es mitad laurel mitad ninfa' >>> imprimeDoble(latoya) Dafne, es mitad laurel mitad ninfa. Dafne, es mitad laurel mitad ninfa. \end{verbatim} Observe un aspecto realmente importante en este caso: el nombre de la variable que pasamos como argumento (\texttt{latoya}) no tiene nada que ver con el nombre del parámetro (\texttt{paso}). No importa cómo se llamaba el valor en su lugar original (el lugar desde donde se invocó); aquí en \texttt{imprimeDoble} llamamos a todo el mundo \texttt{paso}. \section{Las variables y los parámetros son locales} \index{variables locales} \index{locales!variables} Cuando crea una variable dentro de una función, sólo existe dentro de dicha función, y no puede usarla fuera de ella. Por ejemplo, la función \begin{verbatim} >>> def catDoble(parte1, parte2): ... cat = parte1 + parte2 ... imprimeDoble(cat) ... >>> \end{verbatim} toma dos argumentos, los concatena y luego imprime el resultado dos veces. Podemos llamar a la función con dos cadenas: \begin{verbatim} >>> cantus1 = "Die Jesu domine, " >>> cantus2 = "Dona eis requiem." >>> catDoble(cantus1, cantus2) Die Jesu domine, Dona eis requiem. Die Jesu domine, Dona eis requiem. \end{verbatim} Cuando \texttt{catDoble} termina, la variable \texttt{cat} se destruye. Si tratásemos de imprimirla, obtendríamos un error: \begin{verbatim} >>> print cat NameError: cat \end{verbatim} Los parámetros también son locales. Por ejemplo, una vez fuera de la función \texttt{imprimeDoble}, no existe nada llamado \texttt{paso}. Si trata de usarla, Python se quejará. \section{Diagramas de pila} \label{stackdiagram} \index{diagramas de pila} Para mantener el rastro de qué variables pueden usarse y dónde, a veces es útil dibujar un \textbf{diagrama de pila}. Como los diagramas de estado, los diagramas de pila muestran el valor de cada variable, pero también muestran la función a la que cada variable pertenece. Cada función se representa por una caja con el nombre de la función junto a él. Los parámetros y variables que pertenecen a una función van dentro. Por ejemplo, el diagrama de stack para el programa anterior tiene este aspecto: \vspace{0.1in} \centerline{\includegraphics{../illustrations/stack.eps} } \vspace{0.1in} El orden de la pila muestra el flujo de ejecución. \texttt{imprimeDoble} fue llamado por \texttt{catDoble} y a \texttt{catDoble} lo invocó \texttt{\_\_main\_\_}, que es un nombre especial de la función más alta. Cuando crea una variable fuera de cualquier función, pertenece a \texttt{\_\_main\_\_}. En cada caso, el parámetro se refiere al mismo valor que el argumento correspondiente. Así que \texttt{parte1} en \texttt{catDoble} tiene el mismo valor que \texttt{cantus1} en \texttt{\_\_main\_\_}. Si sucede un error durante la llamada a una función, Python imprime el nombre de la función y el nombre de la función que la llamó, y el nombre de la función que llamó a {\em ésa}, y así hasta {\tt \_\_main\_\_}. Por ejemplo, si intentamos acceder a {\tt cat} desde {\tt imprimeDoble}, provocaremos un {\tt NameError}: \beforeverb \begin{verbatim} Traceback (innermost last): File "test.py", line 13, in __main__ catDoble(cantus1, cantus2) File "test.py", line 5, in catDoble imprimeDoble(cat) File "test.py", line 9, in imprimeDoble print cat NameError: cat \end{verbatim} \afterverb % Esta lista de funciones de llama {\bf traceback} (traza inversa). Le dice a usted en qué archivo de programa sucedió el error, y en qué línea, y qué funciones se ejecutaban en ese momento. También muestra la línea de código que causó el error. \index{traceback} Fíjese en la similaridad entre la traza inversa y el diagrama de pila. No es una coincidencia. \section{Funciones con resultado} Seguramente ha notado ya que algunas de las funciones que estamos usando, igual que las funciones matemáticas, devuelven un resultado. Otras funciones, como \texttt{nueva\_linea}, llevan a cabo una acción pero no devuelven un valor. Ello suscita varias preguntas: \begin{enumerate} \item ¿Qué sucede si llama usted a uana función y no hace nada con el resultado (es decir, no lo asigna a una variable ni lo usa como parte de una expresión más amplia)? \item ¿Qué sucede si usa una función sin resultado como parte de una expresión, por ejemplo \texttt{nueva\_linea() + 7}? \item ¿Se pueden escribir funciones que devuelvan resultados, o debemos limitarnos a funcinoes simples como \texttt{nueva\_linea} e \texttt{imprimeDoble}? \end{enumerate} La respuesta a la tercera pregunta es {}``sí, puede escribir funciones que devuelvan valores'', y lo haremos en el capítulo 5. \begin{quote} \emph{Como actividad final, consteste a las otras dos preguntas intentando hacerlas en la práctica. Cada vez que tenga una duda sobre lo que es legal o ilegal en Python, perguntar al intérprete será una buena manera de averiguarlo.} \end{quote} \section{Glosario} \begin{description} \item [llamada~a~función:] Una sentencia que ejecuta una función. Está compuesta por el nombre de la función más una lista de argumentos encerrados entre paréntesis. \item [argumento:] Valor que se le pasa a una función cuando se la llama. El valor se asigna al parámetro correspondiente de la función. \item [valor~de~retorno:] Es el resultado de una función. Si se usa una llamada a función a modo de expresión, el valor de retorno es el valor de la expresión. \item [conversión de tipo:] Una sentencia explícita que toma un valor de un tipo y calcula el valor correspondiente de otro tipo. \item [coerción:] Conversión tipos que ocurre automáticamente de acuerdo con las reglas de coerción de Python. \item [módulo:] Fichero que contiene una colección de funciones y clases relacionadas. \item [notación de punto:] La sintaxis para llamar a una función de otro módulo, especificando el nombre del módulo, seguido por un punto y el nombre de la función. \item [función:] Secuencia de sentencias etiquetadas que llevan a cabo determinada operación de utilidad. Las funciones pueden tomar parámetros o no, y pueden producir un resultado o no. \item [definición~de~función:] Sentencia que crea una nueva función, especificando su nombre, parámetros y las sentencias que ejecuta. \item [flujo~de~ejecución:] Orden en el que se ejecutan las sentencias durante la ejecución de un programa. \item [parámetro:]Nombre que se usa dentro de una función para referirse a el valor que se le pasa como argumento. \item [variable~local:]variable definida dentro de una función. Las variables locales sólo pueden usarse dentro de su función. \item [diagrama~de~pila:]Representación gráfica de una pila de funciones, sus variables y los valores a los que se refieren. \item [traza inversa:] (traceback en inglés) Una lista de las funciones en curso de ejecución, presentadas cuando sucede un error en tiempo de ejecución. \index{llamada a función} \index{valor de retorno} \index{argumento} \index{coerción} \index{conversión de tipo} \index{módulo} \index{función} \index {notación de punto} \index{definición de función} \index{flujo de ejecución} \index{parámetro} \index{variable local} \index{diagrama de pila} \index {traza inversa} \end{description} %\end{document}


Next Up Previous Hi Index