Aparte de las funciones integradas al lenguaje (built-in) y de las que se puedan importar de bibliotecas externas, se pueden integrar al lenguaje funciones definidas por el usuario.
Para crear una función es esencial definir con total precisión qué queremos que haga.
Es decir:
Vamos a crear una función que convierta un valor de temperatura en grados Fahrenheit a grados Celsius (ver Ejemplo 1.1)
La función va a tener un único argumento, que es el valor de temperatura en Fahrenheit, y va a devolver el valor en grados Celsius.
def fahrenheit_to_celsius(grados_fahrenheit):
grados_celsius = (grados_fahrenheit-32)*5/9
return grados_celsius
temp1 = fahrenheit_to_celsius(80)
print(temp1)
print(fahrenheit_to_celsius(66))
temp2 = 75
print(fahrenheit_to_celsius(temp2))
Vamos a crear una función que, partir de una frecuencia dada, calcule la frecuencia a un número determinado de cents de distancia (ver Ejemplo 1.2).
def cents_a_frecuencia(frec_inicial, cents):
frec_final = frec_inicial*(2**(cents/1200))
return frec_final
frec1 = 440
frec2 = cents_a_frecuencia(frec1, 50)
print(frec2)
frec3 = cents_a_frecuencia(frec1, -1200)
print(frec3)
Vamos a definir una función que, dado un número de divisiones iguales de un intervalo "octavante" (no necesariamente 2), calcule el multiplicador de frecuencia entre grados sucesivos (por ejemplo, para la división en 12 partes iguales de la octava 2:1, el valor 1.0594630943592953). (ver Ejercicio 1.1)
Solución: Para una cantidad N de divisiones de un intervalo O, el valor del multiplicador de frecuencia entre grados conjuntos es raíz N-ésima de O.
def division(grados, octava):
factor = octava**(1/grados)
return factor
et12 = division(12, 2)
print(et12)
et19 = division(19, 2)
print(et19)
foo = division(23, 3)
print(foo)
Por defecto, los argumentos que se pasan a la función son interpretados en el orden en que están los parámetros en la definición (argumentos posicionales). Pero se pueden pasar los argumentos en cualquier orden arbitrario, usando los nombres de los parámetros (argumentos por clave).
et12 = division(octava=2, grados=12)
print(et12)
En una función podemos determinar que un parámetro sea opcional y adquiera un valor por defecto, asignándole un valor en la definición de la función.
Por ejemplo, en la función anterior podemos decidir que por defecto el valor de octava es 2, y sólo necesitamos explicitar ese parámetro cuando queremos un valor diferente.
def division(grados, octava=2):
factor = octava**(1/grados)
return factor
et12 = division(12)
print(et12)
et19 = division(19)
print(et19)
foo = division(23,3)
print(foo)
Por defecto, las variables en Python son locales. Esto quiere decir que las variables definidas y utilizadas en el bloque de código de una función, sólo tienen existencia dentro de la misma, y no interfieren con otras variables del resto del código.
A su vez, las variables existentes fuera de una función, no son visibles dentro de la misma.
var1 = "variable original"
def varmod():
var1 = "variable modificada"
print(var1)
print(var1)
varmod()
print(var1)
En caso de que sea conveniente o necesario, una variable puede convertirse en global declarándola explícitamente como tal con la instrucción global.
var1 = "variable original"
def globvar():
global var1
var1 = "variable global modificada"
print(var1)
globvar()
print(var1)
Como se puede ver, después de llamar a la función globvar(), la variable var1 queda modificada.
En general, este procedimiento debe utilizarse con precaución.
Las docstrings (o documentation strings) son, como lo dice su nombre, cadenas de texto que sirven para documentar diversos aspectos de una función: qué hace, el valor de sus parámetros, qué tipos de argumentos recibe, qué tipo de objeto devuelve, etc.
Aparecen como primera instrucción en el cuerpo de la función, a continuación de su declaración, y por convención van delimitadas por triple comillas.
def fahrenheit_to_celsius(grados_fahrenheit):
"""convierte una temperatura en grados Fahrenheit
a grados Celsius"""
grados_celsius = (grados_fahrenheit-32)*5/9
return grados_celsius
En casos simples, la doctring consiste en una sola línea, con una descripción sumaria de la función.
Funciones más complejas pueden requerir una descripción más detallada. En ese caso, por convención se deja una línea en blanco después de la primera línea con la descripción sumaria, y luego se procede a expandir la descripción.
Una funcionalidad valiosa de las docstrings, es que Python genera a partir de ellas su propia documentación, que se puede invocar en línea mediante la función help() vista más arriba.
help(fahrenheit_to_celsius)
Al invocar la función help() pasándole como argumento el nombre de una función, nos devuelve la siguiente información:
Se pueden definir funciones que no tengan parámetros de entrada. En ese caso, la función ejecuta el mismo código cada vez que es invocada.
def alarma():
print("riiiiiiiiing")
alarma()
La función anterior tampoco utiliza la intrucción return para devolver un valor.
En realidad, toda función en Python devuelve un valor. Cuando no se utiliza la instrucción return para devolver un valor explícito, la función devuelve el valor None.
valor = alarma()
print("El valor que devuelve la función alarma() es", valor)
Los comentarios en el código tienen una vital importancia en el desarrollo de todo programa.
Son ignorados por el intérprete y no generan ningún tipo de código, pero constituyen una ayuda esencial tanto para quien está desarrollando el programa, como para otras personas que lean el código.
Entre otras, algunas de las funciones más importantes que pueden cumplir los comentarios en un programa, son:
El signo para indicar el comienzo de un comentario en Python es la almohadilla o numeral (#), a partir del cual y hasta el fin de la línea, todo se considera un comentario y es ignorado por el intérprete.
El carácter # puede estar al comienzo de línea (en cuyo caso toda la línea será ignorada), o después de finalizar una instrucción válida de código.
Como ejemplo, se muestra una forma posible de comentar el programa del Ejemplo 1.2 (clase 1).
# programa que calcula la frecuencia resultante al transportar
# una frecuencia inicial dada una cierta cantidad de cents
# primero se pide al usuario que ingrese la frecuencia incial
# y la cantidad de cents a ser transportada
# se piden los argumentos de entrada
# y se convierten los strings en un números flotantes
frec_inicial = float(input("ingrese la frecuencia inicial: "))
cents = float(input("ingrese la cantidad de cents: "))
# se calcula la frecuencia resultante
frec_final = frec_inicial*(2**(cents/1200))
print("frecuencia final: ", frec_final)
En un programa tan corto y sencillo quizás no sean necesarios tantos comentarios. Es importante escribir programas suficientemente comentados, pero no recargar el código con comentarios innecesarios de cosas obvias.
Por ejemplo, el comentario siguiente sería inadecuado, por resultar obvio de la propia instrucción:
# imprime la frecuencia resultante en la pantalla
print("frecuencia final: ", frec_final)
A diferencia de otros lenguajes de programación, Python no dispone de un método para delimitar bloques de comentarios de varias líneas.
Las alternativas para introducir comentarios multilíneas son: