Funciones#
En la clase pasada vimos los fundamentos del lenguaje: palabras reservadas, tipos de variables y estructuras de control de flujo. Hoy vamos a ver un concepto fundamental en todo lenguaje de programación: las funciones. Las funciones permiten estructurar el código de un programa en unidades que se ocupan de una tarea particular.
Ya vimos una función importante, que es la que me permite ver el resultado de un programa: la función print
.
Las funciones reciben una cierta cantidad de datos de entrada, denominados argumentos de la función, y pueden devolver (o no) uno o varios resultados.
Para definir funciones, usamos la palabra reservada def
. Empecemos definiendo una función parecida a print
:
# Definición (o declaración) de la función
def saluda():
print('Chau mundo!')
Hemos definido la función saluda
que no recibe ningún argumento. La función tiene como nombre saluda
, y no recibe ningún argumento, de allí los paréntesis vacíos ()
. Nótese también la indentación, que es obligatoria también en este caso, al igual que en las estructuras de control.
¿Cómo se llama, es decir, se ejecuta, a la función?
# Ejecutamos la función saluda()
saluda()
Chau mundo!
def saluda():
print('Hola mundo!')
saluda()
Hola mundo!
# Definimos la función
def saluda_a(amigo):
print('Hello, ', amigo," !")
# Ejecutamos la función
saluda_a("John")
saluda_a(3)
Hello, John !
Hello, 3 !
mi_amigo = "Carlos"
saluda_a(mi_amigo)
Hello, Carlos !
No puedo llamar a esta función con más argumentos:
lennon = "John"
mccartney = "Paul"
saluda_a(lennon,mccartney)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[6], line 3
1 lennon = "John"
2 mccartney = "Paul"
----> 3 saluda_a(lennon,mccartney)
TypeError: saluda_a() takes 1 positional argument but 2 were given
Ni con menos:
saluda_a()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-11-279f2a3e3b85> in <module>
----> 1 saluda_a()
TypeError: saluda_a() missing 1 required positional argument: 'amigo'
Las funciones pueden retornar valores, se usa la palabra reservada return
:
# x es el argumento formal de la función
def al_cuadrado(x):
""" Esta función eleva al cuadrado
el valor de entrada"""
z = 3
print("z adentro de al_cuadrado:", z)
y = x**2
# Valor de salida de la función
return y
a = 2
# a es el argumento real de la función
b = al_cuadrado(a)
y = 5
print(a," al cuadrado es:", b)
print("y afuera de al_cuadrado:", y)
print("z afuera de al_cuadrado:", z)
z adentro de al_cuadrado: 3
2 al cuadrado es: 4
y afuera de al_cuadrado: 5
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-17-a1068c403541> in <module>
14 print(a," al cuadrado es:", b)
15 print("y afuera de al_cuadrado:", y)
---> 16 print("z afuera de al_cuadrado:", z)
NameError: name 'z' is not defined
c = 9
d = al_cuadrado(c)
print(d)
Varias cosas importantes a notar
Puedo definir variables dentro de una función. De hecho, cualquier cosa que se pueda hacer en Python, se puede hacer dentro de una función
En la expresión
b = al_cuadrado(a)
asignamos el resultado de la función a la variableb
.x
se denomina argumentoformal
de la funcióna
es el argumentoreal
de la función, cuando la usamos enb = al_cuadrado(a)
. Es decir, que cuando la función se ejecuta, el argumento formalx
adopta el valor del argumento reala
. Esto es exactamente lo mismo que cuando en matemática hacemos $\(f(x) = x^2\)\( y dada \)a=23\(, queremos calcular \)f(a)\(. Simplemente reemplazamos el valor de \)a\( en \)x$ en la definición de la función.
Hay que estar atento al tipo de argumento
john = "Lennon"
al_cuadrado(john)
z adentro de al_cuadrado: 3
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-18-8ec7c819cbb0> in <module>
1 john = "Lennon"
----> 2 al_cuadrado(john)
<ipython-input-17-a1068c403541> in al_cuadrado(x)
4 z = 3
5 print("z adentro de al_cuadrado:", z)
----> 6 y = x**2
7 # Valor de salida de la función
8 return y
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
def al_cubo(x):
y = x*x*x
return y
def ala_cuarta(x):
y = x**4
return y
b = al_cubo(3)
print(b)
b = ala_cuarta(b)
print(b)
27
531441
def al_cubo_no_devuelve_nada(x):
y = x*x*x
# acá falta un return y....
b = al_cubo_no_devuelve_nada(4)
print(b)
None
Ejemplos#
La secuencia de Fibonacci#
Una de las secuencias más importantes en matemática (y en el arte!) es la secuencia de Fibonacci: $\( f_0 = 0\)\( \)\( f_1 = 1\)\( \)\( f_n = f_{n-1} + f_{n-2}\)$
La secuencia de Fibonacci es responsable del número de oro: $\(\phi = \lim_{n\rightarrow \infty} \frac{f_n}{f_{n-1}} = \frac{1 + \sqrt{5}}{2}\)$
def fib(n):
"""Devuelve una lista con los términos
de la serie de Fibonacci hasta n."""
result = [0,1]
i = 2
while i < n:
fn = result[i-1] + result[i-2]
result.append(fn)
print("iteración: ",i, "sec: ",result)
i = i + 1
return result
#
# Arreglar fib(n) para que fib(0) de como
# resultado 0
#
fib(0)
[0, 1]
Múltiples argumentos de entrada y salida#
def divide_seguro(x,y):
""" Calcula x/y, pero devuelve un
error si y es cero"""
if(y==0):
return None,"Error: y vale 0"
else:
return x/y, "Ok"
a = 8.2
b = 0
cociente, result = divide_seguro(a,b)
print("cociente: ",cociente,", result:",result)
c = 2.5
cociente, result = divide_seguro(a,c)
print("cociente: ",cociente,", result:",result)
cociente: None , result: Error: y vale 0
cociente: 3.28 , result: Ok
Un poco de ayuda de mis amigos#
La función help
nos da ayuda sobre las funciones, ya sean del lenguaje o las que programamos, si es que tienen el docstring
adecuado.
help(print)
Help on built-in function print in module builtins:
print(...)
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
help(fib)
Help on function fib in module __main__:
fib(n)
Devuelve una lista con los términos
de la serie de Fibonacci hasta n.
help(divide_seguro)
Help on function divide_seguro in module __main__:
divide_seguro(x, y)
Calcula x/y, pero devuelve un
error si y es cero
Ahora vamos al TP2…
Argumentos opcionales#
def caida_libre(t, h0, v0 = 0., g=9.8):
"""
Devuelve la velocidad y la posición de una partícula en
caída libre para condiciones iniciales dadas
"""
v = v0 - g*t
h = h0 - v0*t - g*t**2/2.
return v, h
v1, h1 = caida_libre(10, 1000)
print(v1)
print(h1)
v1, h1 = caida_libre(10, 1000, g = 12)
print(v1)
print(h1)
Ámbito de las variables#
def func1(x):
print('x entró a la función con el valor', x)
x = 2
print('El nuevo valor de x es', x)
y = 50
print('Originalmente x vale',y)
func1(y)
print('Ahora x vale',y)
x = [50]
print('Originalmente x vale',x)
def func2(x):
print('x entró a la función con el valor', x)
x = [2]
print('El nuevo valor de x es', x)
func2(x)
print('Ahora x vale',x)
x = [50]
print('Originalmente x vale',x)
def func3(x):
print('x entró a la función con el valor', x)
x[0] = 2
print('El nuevo valor de x es', x)
func3(x)
print('Ahora x vale',x)
x = [50]
print('Originalmente x vale',x)
def func3(x):
print('x entró a la función con el valor', x)
x = 'lala'
print('El nuevo valor de x es', x)
func3(x)
print('Ahora x vale',x)
x = [1,2,3,4,5]
print('Originalmente x vale',x)
def func3(x):
print('x entró a la función con el valor', x)
x[2] = 108
print('El nuevo valor de x es', x)
func3(x)
print('Ahora x vale',x)
Algo de I/O#
Con las siglas I/O se hace referencia usualmente a los procedimientos de entrada y salida (del inglés, Input/Output). Esto se refiere la mayor parte de las veces a leer o escribir datos, ya sea de pantalla, archivo, etc.
Ya vimos la función print
que escribe en la pantalla. Su contrapartida es la función input
, que permite leer datos por pantalla:
algo_ingresado = input('Ingrese algo: ')
print(algo_ingresado)
print("El tipo de dato ingresado es:",type(algo_ingresado))
Ingrese algo: 3
3
El tipo de dato ingresado es: <class 'str'>
Al igual que la función print
, que siempre escribe un tipo string
, input
siempre recibe el tipo string
.
Cargar y escribir archivos de texto#
Otra operación fundamental de I/O es la carga de datos desde archivos, y su escritura:
writeme = open('ejemplo.txt','w',encoding = 'utf-8') # 'w' es write, es decir, escribir
texto = 'Esta es la primer línea,\nesta es la segunda\ny esta es la tercera.'
writeme.write(texto)
writeme.close()
Codificaciones de texto: ASCII UTF-8 etc. etc.
readme = open('ejemplo.txt')
texto_leido = readme.read()
print(texto_leido)
readme.close()
Esta es la primer línea,
esta es la segunda
y esta es la tercera,
y le agrego una cuarta línea.
readme = open('ejemplo.txt')
texto_leido = readme.read(16)
print(texto_leido)
mas_texto_leido = readme.read()
print(mas_texto_leido)
readme.close()
Esta es la prime
r línea,
esta es la segunda
y esta es la tercera,
y le agrego una cuarta línea.
readme = open('ejemplo.txt')
for linea in readme:
print(linea)
readme.close()
Esta es la primer línea,
esta es la segunda
y esta es la tercera,
y le agrego una cuarta línea.
readme = open('ejemplo.txt')
lineas = readme.readlines()
print(type(lineas))
print(len(lineas))
print(lineas[0])
print(lineas)
<class 'list'>
4
Esta es la primer línea,
['Esta es la primer línea,\n', 'esta es la segunda\n', 'y esta es la tercera,\n', 'y le agrego una cuarta línea.']