Además de la sentencia while, recién presentada, Python conoce las sentencias de control de flujo comunes de otros lenguajes, aunque con sabor propio.
Quizá la mejor conocida de las construcciones es if (si). Por ejemplo:
>>> x = int(raw_input("Introduce un número: ")) >>> if x < 0: ... x = 0 ... print 'Negativo cambiado a cero' ... elif x == 0: ... print 'Cero' ... elif x == 1: ... print 'Uno' ... else: ... print 'Más' ...
Puede haber cero o más partes elif y la parte else (si no) es opcional. La palabra clave `elif' es una abreviatura de `else if' y evita el sagrado excesivo. Una secuencia if ... elif ... elif ... es el sustituto de las sentencias switch o case de otros lenguajes.
La construcción for (para) es un poco diferente a lo acostumbrado en C o Pascal. En lugar de recorrer siempre una progresión aritmética (como en Pascal) o dejar al programador total libertad de elección de inicialización, comprobación y salto de paso (como en C), el for de Python recorre los elementos de una secuencia (por ejemplo, una lista o cadena), en el orden en que aparecen en la secuencia. Por ejemplo:
>>> # Medir algunas cadenas: ... a = ['gato', 'ventana', 'defenestrar'] >>> for x in a: ... print x, len(x) ... gato 4 ventana 7 defenestrar 11
No es aconsejable modificar la secuencia que se está recorriendo (lo que sólo puede ocurrir en secuencias mutables, por ejemplo, listas). Si se necesita modificar la lista recorrida, por ejemplo, para duplicar los elementos, hay que recorrer una copia. La notación de corte hace esto muy cómodo.
>>> for x in a[:]: # hacer una copia por corte de la lista entera ... if len(x) > 7: a.insert(0, x) ... >>> a ['defenestrar', 'gato', 'ventana', 'defenestrar']
Si lo que necesitas es recorrer una secuencia de números, la función interna range() viene de perlas. Genera listas con progresiones aritméticas, por ejemplo:
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
El punto final indicado nunca es parte de la lista generada, así que
range(10)
genera una lista de 10 valores, justo los índices legales
de los elementos de una secuencia de longitud 10. Es posible hacer que el
rango arranque en otro número o especificar un incremento diferente (incluso
negativo). Este incremento se llama paso (step):
>>> range(5, 10) [5, 6, 7, 8, 9] >>> range(0, 10, 3) [0, 3, 6, 9] >>> range(-10, -100, -30) [-10, -40, -70]
Para recorrer los índices de una secuencia, combina range() y len() de este modo:
>>> a = ['Cinco', 'lobitos', 'tiene', 'la', 'loba'] >>> for i in range(len(a)): ... print i, a[i] ... 0 Cinco 1 lobitos 2 tiene 3 la 4 loba
La sentencia break (romper), como en C, salta del bucle for o while en curso más interno.
La sentencia continue (continuar), también un préstamo de C, hace que siga la siguiente iteración del bucle.
Las construcciones de bucle pueden tener una cláusula else
. Ésta se
ejecuta, si existe, cuando se termina el bucle por agotamiento de la lista
(con for) o cuando la condición se hace falsa (con
while), pero no cuando se termina el bucle con
break. Para aclarar esto
último, valga un ejemplo, que busca números primos:
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, '=', x, '*', n/x ... break ... else: ... print n, 'es primo' ... 2 es primo 3 es primo 4 = 2 * 2 5 es primo 6 = 2 * 3 7 es primo 8 = 2 * 4 9 = 3 * 3
La sentencia pass no hace nada. Se puede utilizar cuando hace falta una sentencia sintácticamente pero no hace falta hacer nada. Por ejemplo:
>>> while 1: ... pass # Espera activamente una interrupción de teclado ...
Se puede crear una función que escriba la serie de Fibonacci hasta un límite superior arbitrario:
>>> def fib(n): # escribir la serie Fibonacci hasta n ... "escribir la serie Fibonacci hasta n" ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # Y ahora llamamos a la función recién definida: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
La palabra clave def introduce una definición de función. Debe ir seguida del nombre de la función y la lista entre paréntesis de los parámetros formales. Las sentencias que forman el cuerpo de la función empiezan en la siguiente línea y deben ir sangradas. La primera sentencia del cuerpo de la función puede ser una constante de cadena: esta cadena es la documentación de la función o docstring.
Existen herramientas para producir automáticamente documentación impresa/electrónica o permitir al usuario navegar por el código interactivamente. Es una buena práctica incluir documentación en el código que escribas, así que intenta hacer de ello un hábito.
La ejecución de una función introduce una tabla de símbolos nueva para las variables locales de Python. En concreto, todas las asignaciones de variables de una función almacenan el valor en la tabla de símbolos local; por lo que las referencias a variables primero miran en la tabla de símbolos local, luego en la tabla de símbolos global y, por último, en la tabla de nombres internos. Por ello no se puede asignar un valor a una variable global dentro de una función (salvo que esté mencionada en una sentencia global), pero se puede hacer referencia a ellas.
Los parámetros reales (argumentos) de una llamada a una función se introducen en la tabla de símbolos local de la función aludida al llamarla: los argumentos se pasan por valor (en donde el valor siempre es una referencia a un objeto, no el valor del objeto4.1. Cuando una función llama a otra función, se crea una tabla de símbolos locales nueva para esa llamada.
Una definición de función introduce el nombre de la función en la tabla de símbolos vigente. El valor del nombre de la función tiene un tipo reconocido por el intérprete como función definida por el usuario. Se puede asignar este valor a otro nombre y usar éste, a su vez, como función que es. Esto sirve de mecanismo de renombrado genérico:
>>> fib <function object at 10042ed0> >>> f = fib >>> f(100) 1 1 2 3 5 8 13 21 34 55 89
Se puede objetar que fib
no es una función, sino un procedimiento. En
Python, como en C, los procedimientos son simplemente funciones que no
devuelven ningún valor. De hecho, hablando técnicamente, los
procedimientos sí devuelven un valor, sólo que bastante aburrido.
Este valor se llama None
(es un nombre interno).
El intérprete suele omitir la escritura del valor de None
,
si es el único valor que se fuera a escribir. Se puede
ver si realmente lo deseas:
>>> print fib(0) None
Resulta simple escribir una función que devuelva una lista de los números de la serie de Fibonacci, en lugar de mostrarla:
>>> def fib2(n): # Devolver la serie de Fibonacci hasta n ... "Devolver una lista con los números de la serie de Fibonacci hasta n" ... resultado = [] ... a, b = 0, 1 ... while b < n: ... resultado.append(b) # ver más abajo ... a, b = b, a+b ... return resultado ... >>> f100 = fib2(100) # llamarlo >>> f100 # escribir el resultado [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
resultado.append(b)
llama a un método del objeto
lista resultado
. Un método es una función que `pertenece' a un objeto
y se llama obj.nombreMétodo
, donde obj
es un objeto (que
puede resultar de una expresión) y nombreMétodo
es el nombre del
método definido por el tipo del objeto. Los métodos de diferentes tipos pueden
tener el mismo nombre sin ambigüedad. Es posible definir tus propios tipos de
objetos y métodos, utilizando clases, según se discute más adelante en
esta guía. El método append() (empalmar), mostrado en el ejemplo, está
definido para objetos lista: Añade un elemento nuevo al final de la lista. En
este ejemplo es equivalente a "resultado = resultado + [b]", pero más
eficaz.
También es posible definir funciones con un número variable de argumentos. Existen tres formas, que se pueden combinar.
Es la forma más útil de especificar un valor por omisión para uno o más de los argumentos. Esto crea una función a la que se puede llamar con menos argumentos de los que tiene definidos, por ejemplo:
def confirmar(indicador, intentos=4, queja='¡O sí o no!'): while 1: respuesta = raw_input(indicador) if respuesta in ('s', 'si', 'sí'): return 1 if respuesta in ('n', 'no', 'nanay', 'nasti'): return 0 intentos = intentos - 1 if intentos < 0: raise IOError, 'Usuario rechazado' print queja
Se puede llamar a esta función así: confirmar('¿Quiere salir?')
o
así: confirmar('¿Desea borrar el fichero?', 2)
.
Los valores por omisión se evalúan en el instante de definición de la función en el ámbito de definición, así:
i = 5 def f(arg = i): print arg i = 6 f()
mostrará 5
.
Aviso importante: El argumento por omisión se evalúa una sola vez. Esto lleva a diferentes resultados cuando el valor por omisión es un objeto mutable, tal como una lista o diccionario. Por ejemplo, la siguiente función acumula los argumentos que se le pasan en sucesivas llamadas:
def f(a, l = []): l.append(a) return l print f(1) print f(2) print f(3)
Esto presenta:
[1] [1, 2] [1, 2, 3]
Si no se desea que el valor por omisión sea compartido por las sucesivas llamadas, se puede escribir la función de este modo:
def f(a, l = None): if l is None: l = [] l.append(a) return l
También se puede llamar a una función utilizando la forma "clave = valor". Por ejemplo, la siguiente función:
def loro(tension, estado='tieso', accion='voom', tipo='Azul noruego'): print "-- Este loro no podría", accion, print "aunque le aplicara", tension, "voltios." print "-- Bello plumaje, el", tipo print "-- ¡Está", estado, "!"
puede invocarse de estas maneras:
loro(1000) loro(accion = 'VOOOOOM', tension = 1000000) loro('mil', estado = 'criando malvas') loro('un millón de', 'desprovisto de vida', 'saltar')
pero las siguientes llamadas serían todas incorrectas:
loro() # falta un argumento obligatorio loro(tension=5.0, 'muerto') # argumento clave seguido por argumento no-clave loro(110, tension=220) # valor de argumento duplicado loro(actor='John Cleese') # clave desconocida
En general, una lista de argumentos debe tener argumentos posicionales seguidos por argumentos clave, donde las claves se seleccionan de los nombres de los parámetros formales. No importa si un parámetro formal tiene valor por omisión o no. Ningún argumento debe recibir valor más de una vez (los nombres de parámetros formales correspondientes a argumentos posicionales no se pueden usar como claves en la misma llamada). He aquí un ejemplo que falla por culpa de esta restricción:
>>> def function(a): ... pass ... >>> function(0, a=0) Traceback (innermost last): File "<stdin>", line 1, in ? TypeError: keyword parameter redefined
Cuando el último parámetro formal tiene la forma **nombre
recibe
un diccionario que contiene todos los argumentos clave cuya clave no se
corresponde con ningún parámetro formal.
Esto se puede combinar con un parámetro formal de la
forma *nombre
(descrito en la siguiente subsección) que recibe una
tupla que contiene los argumentos posicionales que exceden la lista de
parámetros formales (*nombre
debe aparecer antes de **nombre
).
Por ejemplo, si definimos una función como ésta:
def queseria(clase, *argumentos, **claves): print "-- ¿Tiene", clase, '?' print "-- Lo siento, no nos queda", clase for arg in argumentos: print arg print '-'*40 for kw in claves.keys(): print kw, ':', claves[kw]
se puede invocar de estas maneras:
queseria('Limburger', "Chorrea mucho, señor.", "Chorrea mucho, muchísimo.", cliente='John Cleese', tendero='Michael Palin', sketch='Sketch de la quesería')
Y mostraría:
-- ¿Tiene Limburger ? -- Lo siento, no nos queda Limburger Chorrea mucho, señor. Chorrea mucho, muchísimo. ---------------------------------------- cliente : John Cleese tendero : Michael Palin sketch : Sketch de la quesería
Finalmente, la opción menos frecuente es especificar que una función puede llamarse con un número arbitrario de argumentos. Estos argumentos se agruparán en una tupla. Antes del número variable de argumentos puede haber cero o más argumentos normales.
def fprintf(file, formato, *args): file.write(formato % args)
A petición popular, se han añadido a Python algunas características comúnmente halladas en los lenguajes de programación funcional y Lisp. Con la palabra clave lambda es posible crear pequeñas funciones anónimas. Ésta es una función que devuelve la suma de sus dos argumentos: "lambda a, b: a+b". Las formas lambda se pueden utilizar siempre que se necesite un objeto función. Están sintácticamente restringidas a una expresión simple. Semánticamente son un caramelo sintáctico para una definición de función normal. Al igual que las definiciones de funciones anidadas, las formas lambda no pueden hacer referencia a las variables del ámbito que las contiene, aunque esto se puede subsanar mediante el uso juicioso de los valores de argumento por omisión, por ejemplo:
def montar_incrementador(n): return lambda x, incr=n: x+incr
Hay convenciones crecientes sobre el contenido y formato de las cadenas de documentación.
La primera línea debe ser siempre un corto y conciso resumen de lo que debe hacer el objeto. En aras de la brevedad, no debes hacer constar el nombre y tipo del objeto, pues éstos están disponibles mediante otros modos (excepto si el nombre es un verbo que describe el funcionamiento de la función). Esta línea debe empezar por mayúscula y terminar en punto.
Si hay más líneas en la cadena de documentación, la segunda línea debe ir en blanco, separando visualmente el resumen del resto de la descripción. Las siguientes líneas deben ser párrafos que describan las convenciones de llamada de los objetos, sus efectos secundarios, etc.
El analizador de Python no elimina el sangrado de los literales multilínea, así que las herramientas que procesen documentación tienen que eliminar el sangrado si se desea. Esto se realiza del siguiente modo. La primera línea que no está en blanco tras la primera línea de la documentación determina el grado de sangrado de la cadena de documentación entera (no se puede utilizar la primera línea, porque suele estar pegada a las comillas de apertura y su sangrado no es evidente dentro del literal). Se elimina el espacio en blanco ``equivalente'' a este sangrado del principio de todas las líneas de la cadena. No debería haber líneas menos sangradas, pero si las hay se debe eliminar su espacio en blanco inicial. La equivalencia del espacio en blanco se debe realizar tras la expansión de los tabuladores (a 8 espacios, normalmente).
He aquí un ejemplo de una cadena de documentación multilínea:
>>> def mi_funcion(): ... """No hacer nada, pero comentarlo muy bien. ... ... Que no, que no hace nada. ... """ ... pass ... >>> print mi_funcion.__doc__ No hacer nada, pero comentarlo muy bien. Que no, que no hace nada.