[go: up one dir, main page]

0% encontró este documento útil (0 votos)
64 vistas11 páginas

Funciones Python

Este capítulo introduce el concepto de programación modular mediante el uso de funciones en Python. Las funciones permiten dividir un problema grande en subproblemas más pequeños y luego combinar las soluciones a esos subproblemas. Se explican los conceptos básicos de funciones, incluido el uso de parámetros, valores de retorno y alcance. Finalmente, se muestra cómo las funciones pueden combinarse con otras estructuras de datos y de control de flujo de Python para resolver problemas más complejos.

Cargado por

Omar Martinez
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
64 vistas11 páginas

Funciones Python

Este capítulo introduce el concepto de programación modular mediante el uso de funciones en Python. Las funciones permiten dividir un problema grande en subproblemas más pequeños y luego combinar las soluciones a esos subproblemas. Se explican los conceptos básicos de funciones, incluido el uso de parámetros, valores de retorno y alcance. Finalmente, se muestra cómo las funciones pueden combinarse con otras estructuras de datos y de control de flujo de Python para resolver problemas más complejos.

Cargado por

Omar Martinez
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 11

Capítulo 3

Funciones, módulos y control


de entrada y salida

En los primeros dos capítulos se escribieron muchas instrucciones. Algunas


consistieron en cálculos, otras en encontrar información sobre una serie de
datos, como el promedio de unas mediciones, y otras en cortos algoritmos,
como el cálculo de los números de Fibonacci. Como estas tareas eran pequeñas,
bastó con escribir una instrucción tras otra en un solo bloque de código.
En la práctica, sin embargo, los problemas son más complejos. Piénsese
en las tareas de evaluar la calidad de la energía a partir de formas de onda,
de evaluar la estabilidad de un sistema eléctrico simulando contingencias o de
predecir la demanda a partir de enormes bancos de mediciones de potencia.
En casos así, en vez de resolver la tarea completa con una sola secuencia de
instrucciones, conviene resolver tareas más pequeñas y luego orquestar dichas
soluciones. En otras palabras, conviene programar de forma modular.
Este capítulo expone una de las técnicas de programación modular más
populares: la programación con funciones. Estos objetos relacionan, como
en las matemáticas, un valor de entrada con uno de salida, de forma muy
precisa. Su utilidad radica en que una única implementación puede ser reusada
innumerables veces. Así, se alivia la tarea de programación y se reduce el riesgo
de errores. El capítulo termina con la escritura y lectura de archivos.

3.1. Funciones con y sin valores de retorno


Una función es una regla que asocia elementos de dos conjuntos, llamados
dominio y codominio. Específicamente, una función f asocia a cada elemento

1
2 Funciones, módulos y control de entrada y salida

del dominio A un elemento del subdominio B. Esto se escribe formalmente


como f : A → B.
El concepto de función es inherente al ser humano. Es fácil enumerar
ejemplos de funciones en la vida cotidiana. Uno es el hecho de que todas
las personas tengan un número de identificación I: esta es, en esencia, una
función del conjunto «personas» (P ) al conjunto de los números naturales (N);
o sea, es una función I : P → N. Otro ejemplo es la función «madre» M : a
cada elemento del conjunto «personas» (P ) se asocia un elemento «madre»
que también pertenece a dicho conjunto; es decir, es una función M : P → P .
Cuando se habla de la velocidad instantánea de un vehículo se está hablando,
en esencia, de una función temporal: a cada instante de tiempo se asocia un
número, que es la velocidad del vehículo.
Las funciones en Python son igual de generales. Tanto su entrada como
su salida pueden tener cualquier valor que pueda ser asignado a una variable.
Esto incluye los valores booleanos True y False, los números como -5 o 3.14,
las cadenas de caracteres, las listas, las listas de listas... Incluso es posible que
una función reciba o devuelva otras funciones.
Considérese primero una función de la forma f : R → R, como lo es
f (x) = x2 . Su implementación sería

def f(x):
return x^2

La palabra reservada def marca el inicio de la función y es seguida con el


nombre, que en este caso es f. Lo que está entre paréntesis es una variable que
adquirirá el valor dado a la función, conocido como argumento. Así, una vez
que se escriba, por ejemplo,

f(2)

la variable x adquirirá el valor de 2. Después de los argumentos se encuentran


los dos puntos (:), que son los que marcan la definición de dicha función. Al
igual que en los condicionales, el texto que sigue a los dos puntos debe tener
un nivel de sangría hacia la derecha. Una vez que dicha sangría se revierte un
nivel a la izquierda, Python lo interpreta como el final de la definición. En este
caso, la definición consta de una sola sentencia: return x**2. Esto es lo que f
devuelve al pasarle otros argumentos:

>>> def f(x):


... return x**2
...
3.1. Funciones con y sin valores de retorno 3

>>> f(1)
1
>>> f(2)
4
>>> f(3)
9

Dado que la variable x solo existe dentro de la función (su alcance o scope es
local), bien se podría sustituir por cualquier otra variable:

>>> def f(number):


... return number**2
...
>>> f(1)
1
>>> f(2)
4
>>> f(3)
9

Esto demuestra que lo importante de las funciones es únicamente su estructura


interna.
Las funciones no necesariamente deben recibir argumentos. La siguiente es
una función constante:

>>> def g():


... return 1
...
>>> g()
1

Incluso si la función no recibe argumentos, es necesario que después de su


nombre se escriban los paréntesis. De otro modo, Python detecta un error de
sintaxis:

>>> def g:
File "<stdin>", line 1
def g:
^
SyntaxError: invalid syntax
>>> return 1
File "<stdin>", line 1
4 Funciones, módulos y control de entrada y salida

return 1
^
IndentationError: unexpected indent

Tampoco es estrictamente necesario que una función devuelva un valor. (En


este sentido, las funciones en Python difieren de las funciones matemáticas.)

>>> def h():


... print('Hola, mundo.')
...
>>> h()
Hola, mundo.

Si bien una función que no devuelva valores puede parecer inutil, es normal
que esto paso, como cuando se desea que una función opere sobre un archivo.
En ese caso, serían más similares a las subrutinas de otros lenguajes. De este
tipo fue la función que imprimía los números de Fibonacci hasta cierto límite
arbitrario, presentada en la introducción:

>>> def fib(n):


... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a + b
...
>>> fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

Cuando una función no devuelve nada, es equivalente a que tuviera la sentencia


return None al final de su definición.
La función f presentada antes (que devolvía el cuadrado de un número)
luce como una fórmula. Sin embargo, como lo ilustra fib, el contenido de una
función puede ser cualquier secuencia de instrucciones como las que se han
escrito hasta ahora. Es importante que dichas instrucciones hagan referencia a
variables que sean «conocidas» para la función (como sus argumentos) y que
las instrucciones se encuentren con el nivel de sangría correcto. La función que
sigue, por ejemplo, devuelve el valor absoluto de su argumento:

>>> def myabs(x):


... if x > 0:
... return x
... else:
3.1. Funciones con y sin valores de retorno 5

... return -x
...
>>> myabs(3)
3
>>> myabs(-3)
3

La implementación puede ser, por supuesto, más compleja. La siguiente función


determina si un número entre 1 y 100 es primo o no:

def es_primo(n):

if not 1 <= n <= 100:


print('El número debe estar entre 1 y 100')
return None
elif n == 1:
return True
else:
for i in range(2, n):
if n % i == 0:
return False
return True

Que esta función está correcta se puede verificar escribiendo, por ejemplo,
es_primo(10) y es_primo(11); estas llamadas a la función devuelven False
y True, respectivamente.
Conviene analizar la lógica anterior. Primero, se evalúa la expresión boolea-
na not 1 <= n <= 100. Si su valor es True, entonces se imprime una adver-
tencia y la función devuelve None. Si su valor es False, entonces n se encuentra
entre 1 y 100. Como el 1 se encuentra en una condición especial, se le trata
por separado con la sentencia elif y se conviene que siempre se devuelva
True. Finalmente, el resto de posibilidades, que son los números entre 2 y
100, son tratados por igual: se itera por todos los posibles divisores i usando
un bucle for y si en algún momento el número n es divisible por alguno,
entonces la función devuelve False (el número no es primo). Cabe también
observar que i nunca llega a ser igual a n, dando que range siempre itera hasta
n-1. Finalmente, si la función nunca devolvió False, entonces el bucle for
agota todas las posibilidades para i y la funcion devuelve, finalmente, True
(el número es primo).
La implementación funciona porque Python trata de forma especial a la
palabra return. Apenas la encuentra en una función, devuelve el valor que
6 Funciones, módulos y control de entrada y salida

sigue a dicha palabra y sale inmediatamente de la función. Así, cuando se


encuentre return False, nunca llegará al final del bucle y, por lo tanto, no
ejecutará return True.
Las funciones pueden combinarse con las estructuras de datos y de control
de flujo estudiadas hasta ahora, lo cual es sumamente poderoso. Supóngase
que se tienen mediciones de tensiones en pu y se quiere determinar cuántas de
ellas están fuera del intervalo 0,95 pu–1,05 pu. Las mediciones están guardadas
en una lista voltages:

>>> voltages = [0.93, 0.94, 0.99, 1.00, 1.03, 1.06, 1.07]

Para empezar, se puede definir una función que determine si una sola tensión
está fuera de ese rango:

>>> def is_outside(v):


... return False if 0.95 <= v <= 1.05 else True
...

(Aquí se ha aprovechado el azúcar sintáctico que permitía escribir condicionales


en una sola línea.) Después, usando la comprensión de listas unida con los
condicionales, se filtran las tensiones que devuelven True.

>>> wrong_voltages = [v for v in voltages if is_outside(v)]

En el condicional se pudo haber escrito if is_outside(v) == True, pero esto


es innecesario: ya la función is_outside devuelve, de por sí, un valor booleano.
Finalmente, se calcula la longitud de la lista filtrada:

>>> len(wrong_voltages)
4

Con la práctica, es natural prescindir de las variables intermedias (como


wrong_voltages) y que simplemente se escriba todo en una sola sentencia:

>>> outliers = len([v for v in voltages if is_outside(v)])


>>> outliers
4

Si bien algunas funciones son tan sencillas que su lógica puede leerse desde
el código fuente, la mayoría, lamentablemente, no lo son. Para mejorar la
legibilidad, es una muy buena práctica incluir comentarios. Esta sería, de
nuevo, la función es_primo:
3.1. Funciones con y sin valores de retorno 7

def es_primo(n):
'''
Determinar si n es primo o no.

El primer argumento es un entero ubicado entre 1 y 100. Si


no pertenece a ese rango, entonces se devuelve None, caso contrario,
se devuelve True o False.
'''

# Tratar casos fuera del rango


if not 1 <= n <= 100:
print('El número debe estar entre 1 y 100')
return None
# Tratar el 1 (caso especial)
elif n == 1:
return True
# Tratar los demás números (caso genérico)
else:
for i in range(2, n):
if n % i == 0:
return False
# Si la evaluación de la función llegó hasta aquí,
# no se encontraron divisores, así que el número es primo
return True
Además de los comentarios marcados con # , se han utilizado cadenas de
caracteres multilínea, que son las delimitadas por '''. Cuando estas son
utilizadas dentro de funciones, se les llama docstrings. Este nombre se debe a
que su propósito es documentar toda la función: explicar qué recibe, qué hace y
qué devuelve. Es importante que las docstrings sean delimitadas con ''' para
que Python las pueda interpretar como tales. Así, es posible imprimir dicha
cadena con el atributo __doc__ de las funciones. Dada la definición anterior,
print(es_primo.__doc__) resulta en

Determinar si n es primo o no.

El primer argumento es un entero ubicado entre 1 y 100. Si


no pertenece a ese rango, entonces se devuelve None, caso contrario,
se devuelve True o False.
8 Funciones, módulos y control de entrada y salida

La forma recomendada de acceder a dicha docstring es utilizar la función


help(). Hacer help(es_primo) resuta en

Help on function es_primo in module __main__:

es_primo(n)
Determinar si n es primo o no.

El primer argumento es un entero ubicado entre 1 y 100. Si


no pertenece a ese rango, entonces se devuelve None, caso contrario,
se devuelve True o False.

Como los desarrolladores de los módulos estándar suelen incluir docstrings, es


posible hacer help() cuando se desconoce qué hace una función:

>>> import math


>>> help(math.hypot)
Help on built-in function hypot in module math:

hypot(...)
hypot(*coordinates) -> value

Multidimensional Euclidean distance from the origin to a point.

Roughly equivalent to:


sqrt(sum(x**2 for x in coordinates))

For a two dimensional point (x, y), gives the hypotenuse


using the Pythagorean theorem: sqrt(x*x + y*y).

For example, the hypotenuse of a 3/4/5 right triangle is:

>>> hypot(3.0, 4.0)


5.0

3.2. Lectura y escritura de archivos


Otras operaciones que involucran la noción de entrada y salida son la
lectura y escritura de archivos. Ambas operaciones son llevadas a cabo con la
3.2. Lectura y escritura de archivos 9

Cuadro 3.1. Modos de apertura de un archivo.

Modo Significado
'r' abrir para leer (por defecto)
'w' abrir para (sobre)escribir, creando el archivo si no existe
'x' abrir para crear (falla si el archivo ya existe)
'a' abrir para escribir, anexando al final del archivo si ya existe
'b' modo binario
't' modo de texto (por defecto)
'+' abrir un archivo del disco para actualizarlo (leer y escribir)

misma función, que es open. Además, esta función suele utilizarse en conjunto
con la palabra reservada with, dado lugar a la siguiente sintaxis:

with open('ejemplo.txt', 'w') as f:


f.write('Hola, mundo\n')
<demás código ejecutado mientras el archivo está abierto>

La combinación with open marca la apertura de un archivo, que en este caso


es 'ejemplo.txt'. Este archivo puede existir o no, según el modo en que se le
abra. El modo es el segundo argumento de open y en este caso es el carácter
'w'; este corresponde al modo de escritura. En dicho modo, si el archivo no
existe, entonces es creado primero. Otro modo, 'r', que es lectura, arrojaría
un error si el archivo todavía no existiese. Los modos en que se puede abrir un
archivo son mostrados en el cuadro 3.1.
Después de la llamada a open se asocia una variable al archivo recién
abierto: f. Por supuesto, esta variable pudo haber adquirido cualquier nombre,
como file o archivo. Con ella, es posible operar sobre el archivo. Dichas
operaciones deben incluirse dentro del cuerpo de la sentencia with: todas las
instrucciones que se ubiquen un nivel de sangría a la derecha. Una vez que se
haya salido de dicho cuerpo, Python cerrará automáticamente el archivo.
La operación que se especificó en el ejemplo, permitida en el modo 'w'
pero no en el 'r', es la de escritura. Esta se lleva a cabo con el método write.
Al escribir f.write(<string>), se escribirá la cadena <string> en el archivo.
Es importante que el argumento de write siempre sea una cadena, pues si no
el resultado será un error. Dicha cadena será escrita inmediatamente después
del último carácter escrito en el archivo. Esto es ilustrado con las instrucciones

>>> with open('Ejemplo 1.txt', 'w') as f:


... f.write('Primera línea')
10 Funciones, módulos y control de entrada y salida

... f.write('Segunda línea')


...
13
13

que producen un archivo 'Ejemplo 1.txt' que contiene

Primera líneaSegunda línea

Para evitar que todo el contenido quede en una sola línea, suele utilizarse el
carácter '\n'. Así,

>>> with open('Ejemplo 1.txt', 'w') as f:


... f.write('Primera línea\n')
... f.write('Segunda línea')
...
14
13

produciría

Primera línea
Segunda línea

Otro modo muy utilizado es el de lectura. Las siguientes instrucciones


leerían el archivo recién creado:

>>> with open('Ejemplo 1.txt', 'r') as f:


... for line in f:
... print(line)
...
Primera línea

Segunda línea

En esencia, la lectura de archivos siempre se reduce a iterar sobre f. Esto


equivale a iterar sobre los renglones del archivo. Para procesar el contenido
del archivo, se pueden usar todos los métodos estudiados antes. Las siguientes
instrucciones, por ejemplo, se deshacen de los saltos de línea y guardan todas
las palabras en una lista.

>>> all_words = []
>>> with open('Ejemplo 1.txt', 'r') as f:
3.2. Lectura y escritura de archivos 11

... for line in f:


... words = line.strip('\n').split(' ')
... all_words += words
...
>>> all_words
['Primera', 'línea', 'Segunda', 'línea']

También podría gustarte