Tema 10. Funciones

Explicación y conceptos básicos de la definición de Funciones en Python 3.

Función

Función. Una función en Python es una pieza de código reutilizable que solo se ejecuta cuando es llamada.

Se define usando la palabra reservada def y estructura general es la siguiente:

def nombre_funcion(input1, input2, ..., inputn):
  cuerpo de la función
  return output

Observación. La instrucción return finaliza la ejecución de la función y devuelve el resultado que se indica a continuación. Si no se indicase nada, la función finalizaría, pero no retornaría nada.

Como hemos visto, en general, las funciones constan de 3 partes:

  • Inputs (parámetros o argumentos). Son los valores que le pasamos como entrada a la función.

  • Cuerpo. Son todas las operaciones que lleva a cabo la función.

  • Output. Es el resultado que devuelve la función.

Observación. Los parámetros son variables internas de la función. Si probásemos a ejecutar una de dichas variables en el entorno global, nos saltaría un error. Este tema lo trataremos más en detalle más adelante.

Con lo visto anteriormente, a la hora de construir una función hau que hacerse las siguientes preguntas:

  • ¿Qué datos necesita conocer la función? (inputs)

  • ¿Qué hace la función? (cuerpo)

  • ¿Qué devuelve? (output)

Observación. Los inputs y el output son opcionales: podemos definir una función sin necesidad de proporcionarle inputs y sin que nos devuelva nada.

Una vez definida una función, para llamarla utilizamos su nombre seguido de paréntesis:

def my_first_function():
    print("Tu primera función te saluda")
my_first_function()

#RESPUESTA
Tu primera función te saluda

Hemos dicho que tanto los inputs como el output son opcionales. Veamos algunos ejemplos con diferentes casos.

Ejemplo 1

Veamos otro ejemplo que no necesite ningún parámetro y no nos devuelva nada, tal y como ocurría con my_first_function()

def hello_world():
  print("Hola mundo!")
hello_world()

#RESPUESTA
Hola mundo!

Nuestra función hello_world(), cuando es llamada, imprime "Hola mundo!", pero no devuelve absolutamente nada.

Ejemplo 2

Veamos un ejemplo de función que no necesita ningún input, pero que devuelve un output. Por ejemplo, una función que nos devuelve "¡Buenos días!"

def good_morning():
    return "Buenos días"

Ya hemos declarado la función. Si la llamamos, obtenemos el siguiente resultado:

good_morning()

#RESPUESTA
'Buenos días'

Como nos devuelve el saludo, lo podemos guardar en una variable, que será de tipo string

goodMorning = good_morning()
print(goodMorning)
print(type(goodMorning))

#RESPUESTA
Buenos días
<class 'str'>

Ejemplo 3

Veamos ahora un ejemplo de función que no nos devuelva nada, pero que sí toma algún parámetro

def good_morning(name):
  print("¡Buenos días, {}!".format(name))
good_morning(name = "Don Pepito")
good_morning(name = "Don José")

#RESPUESTA
¡Buenos días, Don Pepito!
¡Buenos días, Don José!
good_morning("María")

#RESPUESTA
¡Buenos días, María!

Ahora nuestra función good_morning() recibe como parámetro un nombre y nos muestra por pantalla un "¡Buenos días!" junto con el nombre indicado.

Ejemplo 4

Por último, vamos a crear una función que nos calcule la división entera de dos números y nos retorne el cociente y el resto.

def euclidean_division(x, y):
  q = x // y
  r = x % y
  return q, r

Esta función, a la que hemos llamado euclidean_division, calcula el cociente y el resto de dos números cualesquiera y devuelve como resultado esos dos números calculados.

Utilicemos ahora nuestra función para calcular el cociente y el resto de la división 41÷ 7 euclidean_division(x = 41, y = 7)


#RESPUESTA
(5, 6)
euclidean_division(41, 7)

#RESPUESTA
(5, 6)
euclidean_division(y = 7, x = 41)

#RESPUESTA
(5, 6)

Al llamar a la función e indicarle por parámetros x = 41 e y = 7, hemos obtenido como resultado la tupla (5, 6). El significado de dicho resultado es que el cociente entero de 41 ÷ 7 es 5, mientras que el resto es 6. Efectivamente:

41=75+641 = 7\cdot 5 + 6

También podríamos guardar en variables diferentes los resultados que nos devuelve nuestra función, para poder trabajar con ellos en el entorno global

quotient, remainder = euclidean_division(x = 41, y = 7)
print(quotient)
print(remainder)
print(41 == 7 * quotient + remainder)
#RESPUESTA
5
6
True

EJERCICIO 1:

Vamos a crear una función que cuente y devuelva todas las apariciones de una letra proporcionada por parámetro en una frase también proporcionada por parámetro.

def letter_counter(frase, letra):
    frase = frase.lower()
    count = frase.count(letra)
    return count

letter_counter("hoy no me puedo levantar", "o")
3

Parámetros

Por defecto, una función debe ser llamada con el número correcto de argumentos. Esto es, si la función espera 2 argumentos, tenemos que llamar a la función con esos 2 argumentos. Ni más, ni menos.

def complete_name(name, surname):
  print("El nombre completo es", name, surname)
complete_name("María", "Santos")

#RESPUESTA
El nombre completo es María Santos
complete_name("Juan Gabriel", "Gomila")

#RESPUESTA
El nombre completo es Juan Gabriel Gomila

Si intentamos llamar a la función complete_name() pasando 1 solo parámetro o 3 parámetros, entonces la función devuelve error.

complete_name(name = "María")

#RESPUESTA
TypeError: complete_name() missing 1 required positional argument: 'surname'
complete_name("Juan", "Gabriel", "Gomila")

#RESPUESTA
TypeError: complete_name() takes 2 positional arguments but 3 were given

Número arbitrario de argumentos

Si no sabemos el número de parámetros que van a ser introducidos, entonces añadimos un asterisco * previo al nombre del parámetro en la definición de la función. Los valores introducidos serán guardados en una tupla.

def sum_numbers(*numbers):
  sum = 0
  for n in numbers:
    sum += n
  
  return sum
sum_numbers(1, 2, 3)

#RESPUESTA
6
sum_numbers(2, 4, 6, 8, 10)

#RESPUESTA
30

Número arbitrario de claves de argumento

Hasta ahora hemos visto que al pasar valores por parámetro a la función, podemos hacerlo con la sintaxis clave_argumento = valor o directamente pasar por parámetro el valor siguiendo el orden posicional de la definición de la función:

def complete_name(name, surname):
  print("El nombre completo es", name, surname)
complete_name(name = "María", surname = "Santos")

#RESPUESTA
El nombre completo es María Santos
complete_name(surname = "Santos", name = "María")

#RESPUESTA
El nombre completo es María Santos
complete_name("María", "Santos")

#RESPUESTA
El nombre completo es María Santos

En realidad, los nombres completos pueden tener dos o incluso más apellidos, pero no sabemos si el usuario tiene 1 o 2 o más. Entones, podemos añadir dos asteriscos ** antes del nombre del parámetro para así poder introducir tantos como queramos sin que salte error

def complete_name(name, **surname):
    print("El nombre completo es {}".format(name), end = " ")
    for i in surname.items():
      print("{}".format(i[1]), end = " ")
complete_name(name = "María", surname1 = "Santos", surname2 = "Fernández")

#RESPUESTA
El nombre completo es María Santos Fernández 
complete_name(name = "María", surname = "Santos")

#RESPUESTA
El nombre completo es María Santos 

Parámetros por defecto

Hemos visto que una función en Python puede tener o no parámetros.

En caso de tener, podemos indicar que alguno tenga un valor por defecto.

La función diff() calcula la diferencia entre los dos números que introducimos por parámetros. Podemos hacer que el sustraendo por defecto valga 1 del siguiente modo:

def diff(x, y = 1):
  return x - y
diff(65, 18)

#RESPUESTA
47

Si ahora llamamos a la función indicando únicamente el valor del parámetro x, ocurre lo siguiente:

diff(x = 20)

#RESPUESTA
19

Como resultado hemos obtenido 19, ya que el valor que ha tomado el parámetro y ha sido el que le hemos dicho que tome por defecto, es decir, $y = 1$ y, consecuentemente, $x-y = 20-1 = 19$

EJERCICIO 2

Vamos a crear una función que muestre por pantalla el triángulo de Pascal. Por parámetro se indicará el número de filas a mostrar. Por defecto n valdrá 1.

Para calcular el número combinatorio en Python, utilizaremos el siguiente método:

def choose(n, k):
  """
  Calcula el número combinatorio n sobre k
  """
  import math
  if (n >= k and k >= 0):
    return math.factorial(n) / (math.factorial(k) * math.factorial(n - k))
  else:
    return "No se puede calcular el número factorial indicado"
def pascal_triangle(n = 1):
  print(1)
  for i in range(1, n + 1):
    for k in range(i + 1):
      print(choose(i, k), end = " ")
    print("")

pascal_triangle(5)
#RESPUESTA
1
1.0 1.0 
1.0 2.0 1.0 
1.0 3.0 3.0 1.0 
1.0 4.0 6.0 4.0 1.0 
1.0 5.0 10.0 10.0 5.0 1.0 

Docstring

Docstring. Son comentarios explicativos que ayudan a comprender el funcionamiento de una función.

  • Van entre triple comilla doble.

  • Pueden ser multilínea.

  • Se sitúan al principio de la definición de la función.

Retomando el ejemplo de la división entera, podríamos utilizar docstring del siguiente modo:

def euclidean_division(x, y):
  """
  Esta función calcula el cociente y el resto de la
  división entera de x entre y.

  Args:
    x (int): dividendo
    y (int): divisor (que no puede ser cero)

  Returns:
    (q, r): tupla con el valor de (cociente, resto)
  """
  q = x // y
  r = x % y
  return q, r

Con la ayuda del método .__doc__ podemos acceder directamente a la información indicada en el docstring de una función

print(euclidean_division.__doc__)
#RESPUESTA  
  Esta función calcula el cociente y el resto de la
  división entera de x entre y.

  Args:
    x (int): dividendo
    y (int): divisor (que no puede ser cero)

  Returns:
    (q, r): tupla con el valor de (cociente, resto)
  

Variables de una función

Dentro de una función en Python existen dos tipos de variables:

  • Variable local. Aquella que es creada y solamente existe dentro de la función.

  • Variable global. Aquella que es creada en el entorno global.

Dada la siguiente función:

def arithmetic_operations(x, y):
  sum = x + y
  diff = x - y
  prod = x * y
  div = x / y
  return {"sum": sum,
          "difference": diff,
          "product": prod,
          "division": div}

Si nosotros queremos imprimir por ejemplo el valor que toma la variable prod en el entorno global nos saltará un error, pues esta variable no existe a nivel global porque no ha sido declarada en dicho entorno ya que solamente ha sido declarada a nivel local, dentro de la función arithmetic_operations().

print(arithmetic_operations(x = 5, y = 3))

#RESPUESTA
{'sum': 8, 'difference': 2, 'product': 15, 'division': 1.6666666666666667}
print(prod)

#RESPUESTA
NameError: name 'prod' is not define

Si se diese el caso de que sí hubiese sido definida la variable prod en el entorno global, como lo que ocurre en el siguiente bloque de código, por mucho que la variable local tenga el mimso nombre y por mucho que ejecutemos la función, el valor de la variable global no se ve modificado

prod = 10
print(arithmetic_operations(x = 5, y = 3))
print(prod)

#RESPUESTA
{'sum': 8, 'difference': 2, 'product': 15, 'division': 1.6666666666666667}
10

Si dentro de una función utilizamos la palabra reservada global a una variable local, ésta automáticamente pasa a ser una variable global previamente definida.

Veamos un ejemplo de función que nos devuelve el siguiente número del entero n definido en el entorno global:

n = 7

def next_n():
  global n
  return n + 1

next_n()

#RESPUESTA
8

Paso por copia vs. paso por referencia

Dependiendo del tipo de dato que pasemos por parámetro a la función, podemos diferenciar entre

  • Paso por copia. Se crea una copia local de la variable dentro de la función.

  • Paso por referencia. Se maneja directamente la variable y los cambios realizados dentro de la función afectan también a nivel global.

En general, los tipos de datos básicos como enteros, en coma flotante, strings o booleanos se pasan por copia, mientras que estructuras de datos como listas, diccionarios, conjuntos o tuplas u otros objetos se pasan por referencia.

Un ejemplo de paso por copia sería:

def double_value(n):
    n = n*2
    return n
num = 5
print(double_value(num))
print(num)

#RESPUESTA
10
5

Un ejemplo de paso por referencia sería:

def double_values(ns):
  for i, n in enumerate(ns):
    ns[i] *= 2

  return ns
nums = [1, 2, 3, 4, 5]
print(double_values(nums))
print(nums)

#RESPUESTA
[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]

Para evitar la modificación de la lista original, podemos hacerlo introduciendo por parámetro una copia de dicha lista

nums = [1, 2, 3, 4, 5]
print(double_values(nums[:]))
print(nums)

#RESPUESTA
[2, 4, 6, 8, 10]
[1, 2, 3, 4, 5]

Funciones más complejas

Las funciones pueden ser más completas, pues admiten tanto operadores de decisión como de iteración.

Volviendo al ejemplo 4, la función creada claramente es muy sencilla, pues suponemos que el usuario va a introducir por parámetros números enteros.

Ejercicio.

Mejora la función euclidean_division() para que

  • Compruebe que los números introducidos son enteros. En caso de no ser así, indicar que se ha tomado la parte entera de los valores introducidos.

  • Realice la división entera del mayor parámetro (en valor absoluto) entre el menor parámetro. Esto es, si el usuario introduce x = -2 e y = -10, como 10 > 2, entonces la función debe llevar a cabo la división entera de -10 entre -2.

  • Imprima por pantalla una frase indicando la división realizada y el cociente y el resto obtenidos.

  • Devuelva el cociente y el resto a modo de tupla

def euclidean_division(x, y):
  ints = (x == int(x)) and (y == int(y))
  
  if not ints:
    x = int(x)
    y = int(y)
    print("Se tomarán como parámetros la parte entera de los valores introducidos.")
  
  if abs(x) >= abs(y):
    q = x // y
    r = x % y
    print("Se ha realizado la división {} entre {} y se ha obtenido como cociente q = {} y como resto, r = {}".format(x, y, q, r))

  else:
    q = y // x
    r = y % x
    print("Se ha realizado la división {} entre {} y se ha obtenido como cociente q = {} y como resto, r = {}".format(y, x, q, r))


  return q, r
quotient, remainder = euclidean_division(x = -10.3, y = -5)

#RESPUESTA
Se tomarán como parámetros la parte entera de los valores introducidos.
Se ha realizado la división -10 entre -5 y se ha obtenido como cociente q = 2 y como resto, r = 0
-10 == -5 * quotient + remainder

#RESPUESTA
True
euclidean_division(x = -3, y = 19)

#RESPUESTA
Se ha realizado la división 19 entre -3 y se ha obtenido como cociente q = -7 y como resto, r = -2
(-7, -2)

Ejemplo 5

Veamos una función que dado un número, nos dice si éste es positivo, negativo o vale 0.

def sign(num):
  """
  Función que dado un número devuelve el signo positivo, 
  negativo o cero del mismo

  Args:
    num (int): número del cual queremos hallar su signo

  Returns:
    signo (string): string positivo, negativo o cero
  """
  if num > 0:
    return "Positivo"
  elif num < 0:
    return "Negativo"
  else:
    return "Cero"
print(sign(num = 3.1415))

#RESPUESTA
Positivo
print(sign(num = -100))

#RESPUESTA
Negativo
print(sign(num = 0))

#RESPUESTA
Cero

Ejemplo 6

Veamos ahora una función que contiene un bucle for y que dado un número entero, nos imprime su tabla de multiplicar con sus 10 primeros múltiplos y nos devuelve una lista con todos esos múltiplos:

def multiplication_table10(num):
  """
  Dado un número entero, imprimimos su tabla de multiplicar con
  los 10 primeros múltiplos y devolvemos una lista de los múltiplos. 

  Args:
    num (int): valor del cual vamos a calcular sus tabla de multiplicar

  Returns: 
    multiples (list): lista con los 10 primeros múltiplos de num
  """
  multiples = []
  print("La tabla de multiplicar del {}:".format(num))
  
  for i in range(1, 11):
    multiple = num * i
    print("{} x {} = {}".format(num, i, multiple))
    multiples.append(multiple)
  
  return multiples
multiples7 = multiplication_table10(num = 7)
print(multiples7)
#RESPUESTA
7  x  1  =  7
7  x  2  =  14
7  x  3  =  21
7  x  4  =  28
7  x  5  =  35
7  x  6  =  42
7  x  7  =  49
7  x  8  =  56
7  x  9  =  63
7  x  10  =  70
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70]

Vamos ahora a mejorar la función multiplication_table10() para que si el usuario decide introducir un número que no sea entero, nuestra función le avise y le explique el error que está cometiendo:

def multiplication_table10(num):
  """
  Dado un número entero, primero comprovamos si es entero. 
  Si no lo es, no devolvemos nada.
  Si lo es, imprimimos su tabla de multiplicar con los 10 
  primeros múltiplos y devolvemos una lista de los múltiplos. 

  Args:
    num (int): valor del cual vamos a calcular sus 10 primeros múltiplos

  Returns: 
    multiples (list): lista con los 10 primeros múltiplos de num
  """

  if type(num) != type(1):
    print("El número introducido no es entero")
    return

  multiples = []
  print("La tabla de multiplicar del {}:".format(num))
  
  for i in range(1, 11):
    multiple = num * i
    print("{} x {} = {}".format(num, i, multiple))
    multiples.append(multiple)
  
  return multiples
multiples3 = multiplication_table10(num = 3)
print(multiples3)
#RESPUESTA
La tabla de multiplicar del 3:
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
3 x 10 = 30
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
multiples_float = multiplication_table10(num = "3.7")
print(multiples_float)

#RESPUESTA
El número introducido no es entero
None

Ejemplo 7

Creemos ahora una función que dada una frase acabada en punto, nos devuelva si contiene o no la letra "a" haciendo uso de un bucle while

#Mi respuesta si no hay a da error.
def letter_a(phrase):
    """
    función que dada una frase acabada en punto, 
    nos devuelva si contiene o no la letra "a"

    Args:
        phrase (string): Una frase terminada en punto.

    Return:
        a (string): "La frase contiene la letra a"
                    "La frase no contiene la a"
    """
    if phrase[-1] != ".":
        print("La frase no termina con un punto")
        return -1
    i = 0
    contain = False
    else:
        while phrase[i] != "a":
            i += 1
        else:
            contain = True
        if contain == True:
            a = "La frase contiene la letra a"
        else:
            a = "La frase NO contiene la letra a"
    return a
            
#Ejemplo del profesor
def contains_a(sentence):
  i = 0
  while sentence[i] != ".":
    if sentence[i] == "a":
      return True
    i += 1
  return False
contains_a("El erizo es bonito.")

#RESPUESTA
False
contains_a("El elefante es gigante.")

#RESPUESTA
True

Ejercicio.

Generalizad la función contains_a() a una función llamada contains_letter() que devuelva si una frase cualquiera (no necesariamente acabada en punto) contiene o no la letra indicada también por el usuario. Tenéis que hacerlo únicamente con operadores de decisión e iteración. No vale usar ningún método existente de string.

def contains_letter(sentence, letter):
  for c in sentence:
    if c == letter:
      return True
  return False

contains_letter("Mi amigo es muy inteligente, pero un poco pesado", "t")

#RESPUESTA
True

Funciones recursivas

Función recursiva. Es una función que se llama a sí misma.

¡Cuidado! Hay que tener mucho cuidado con este tipo de funciones porque podemos caer en un bucle infinito. Es decir, que la función no acabara nunca de ejecutarse.

Una función recursiva que entraría en bucle infinito sería la siguiente.

def powers(x, n):
  print(x ** n)
  powers(x, n + 1)

¿Por qué decimos que entra en bulce infinito? Pues porque solo parará si nosotros interrumpimos la ejecución.

Esto se debe a que no le hemos indicado un caso de parada a la función, denominado caso final.

Caso final. Es el caso que indica cuándo debe romperse la recursión. Hay que indicarlo siempre para no caer en un bucle infinito.

En el caso de la función powers(), podemos indicar como caso final cuando el valor resultante supere 1000000. Lo indicamos con un if

def powers(x, n):
  if x ** n > 1000000:
    return x ** n

  print(x ** n)
  powers(x, n + 1)
powers(2, 1)
#RESPUESTA
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288

EJERCICIO 3:

Vamos a crear una función recursiva que lleve a cabo una cuenta atrás.

def countdown(initial):
    """
    Función recursiva que lleva a cabo una cuenta atrás.

    Args:
        initial (int): Número desde el que empezamos la cuenta atrás.

    Return:
        countdown(initial - 1): Para que siga bajando.
    """
    if initial == 0:
       return 0
    else:
        print(initial)
    return(countdown(initial - 1))
countdown(10)

#RESPUESTA
10

EJERCICIO 4:

Vamos a crear una función recursiva que calcule el factorial de un número entero positivo.

def factorial(n):
    """
    función recursiva que calcule el factorial 
    de un número entero positivo.

    Args:
        n (int +): número del que calculamos el 
        factorial.

    Return:
        factorial(n - 1): para sacar el factorial 
        completo.
    """
    if n < 0:
        print("No es un número positivo.")
        return -1
    elif n == 0:
        return 1
    else:
        return n * factorial (n - 1)
factorial(4)

#RESPUESTA
24

Ejemplo 8

Veamos ahora un ejemplo clásico de función recursiva que funciona correctamente.

Queremos una función que nos imprima el término i-ésimo de la sucesión de Fibonacci. Es decir, nosotros le indicamos el índice del término y la función nos devuelve el valor de dicho término.

La sucesión de Fibonacci es

1,1,2,3,5,8,13,1, 1, 2, 3, 5, 8, 13,\dots

Es decir, cada término se obtiene de la suma de los dos anteriores.

F0=F1=1F_0 = F_1 = 1 Fn=Fn1+Fn2,n2F_n = F_{n-1} + F_{n-2}, n\geq 2

Con lo cual, la función que queremos y a la que hemos llamado Fibonacci() es:

def Fibonacci(index):
  if index == 0 or index == 1:
    return 1
  
  return Fibonacci(index - 1) + Fibonacci(index - 2) 

Como veis, le hemos indicado a la función cuando parar. Esto es, el caso final resulta ser cuando el índice vale 0, pues no existen índices negativos.

Fibonacci(index = 7)

#RESPUESTA
21
Fibonacci(8)

#RESPUESTA
34
Fibonacci(30)

#RESPUESTA
1346269

EJERCICIO 5:

Vamos a crear una función que resuelva ecuaciones de primer grado de la forma Ax+B=0 siempre que A≠0 .

def first_grade_eq(A, B):
    """
    Función que resuelva ecuaciones de primer grado 
    de la forma  Ax+B=0  siempre que  A≠0 .

    Args:
        A (int != 0)
        B (int)

    Return:
        result (float): Resultado de la operación.    
    """
    if A == 0:
        print("No se cumplen las normas.")
        return -1
    else:
        result = float(-B / A)
    return result
first_grade_eq(4, -4)

#RESPUESTA
1.0

Funciones helper

Al igual que las funciones pueden llamarse a sí mismas, también pueden llamar a otras funciones.

Función helper. Es una función cuyo propósito es evitar la repetición de código.

Si nos dan la siguiente función

def sign_sum(x, y):
  if x + y > 0:
    print("El resultado de sumar {} más {} es positivo".format(x, y))
  elif x + y == 0:
    print("El resultado de sumar {} más {} es cero".format(x, y))
  else:
    print("El resultado de sumar {} más {} es negativo".format(x, y))
sign_sum(5, 4)
sign_sum(3, -3)
sign_sum(1, -8)
#RESPUESTA
El resultado de sumar 5 más 4 es positivo
El resultado de sumar 3 más -3 es cero
El resultado de sumar 1 más -8 es negativo

Vemos que el print se repite salvo por la última palabra.

Podríamos pensar en crear la función helper siguiente:

def helper_print(x, y, sign):
  print("El resultado de sumar {} más {} es {}.".format(x, y, sign))

Si utilizamos la función helper, la función sign_sum() quedaría modificada del siguiente modo:

def sign_sum(x, y):
  if x + y > 0:
    helper_print(x, y, "positivo")
  elif x + y == 0:
    helper_print(x, y, "cero")
  else:
    helper_print(x, y, "negativo")
sign_sum(5, 4)
sign_sum(3, -3)
sign_sum(1, -8)
#RESPUESTA
El resultado de sumar 5 más 4 es positivo.
El resultado de sumar 3 más -3 es cero.
El resultado de sumar 1 más -8 es negativo.

Con lo cual ya no hay código repetido.

Y como se puede observar, la función original funciona correctamente.

EJERCICIO 5:

Vamos a crear una función que haga de calculadora (suma, resta, producto y división), haciendo uso de funciones helper para mostrar la operación realizada. Pediremos por parámetro tipo de operación ("sum", "subract", "product", "division") y dos números reales. Devolveremos el resultado de la operación correspondiente.

def calc(operation, a, b):
    """
    función que haga de calculadora (suma, resta, 
    producto y división), haciendo uso de funciones 
    helper para mostrar la operación realizada

    Args:
        operation (str): sum, sub, prod, div.
        a (float): Operando 1.
        b (float): Operando 2.

    Return:
        result (float): resultado de la operación.
    """
    if operation == "sum":
        result = a + b
    
    elif operation == "sub":
        result = a - b
    
    elif operation == "prod":
        result = a * b
    
    elif operation == "div":
        result = a / b

    else:
        print("- Operación no soportada.")
        result = "NULL"
        return -1

    if result != "NULL":
        helper_result(operation, a, b)
        return result

def helper_result(operation, a, b):
    """
    Función que muestra por pantalla el resultado de 
    la función calc

    Args:
        Los mismos que calc
    
    Return:
        0.
    """
    if operation == "sum":
        simbol = "+"
    elif operation == "sub":
        simbol = "-"
    elif operation == "prod":
        simbol = "x"
    else:
        simbol = "/"
    
    print("Se ha realizado la operación {} {} {}".format(a, simbol, b))
    return 0
calc("sum", 1, 2)

#RESPUESTA
Se ha realizado la operación 1 + 2
3

REPASO

#EJERCICIO 1:Crea una función que busque todos los divisores del número entero positivo dado por parámetro y devuelva
#una lista con todos los divisores de dicho número.

def divisors(x):
    """
    Función que busca todos los divisores de un
    número entero dado.

    Args:
        x (int): Número del que sacar los divisores.
    
    Return:
        div (list): Lista con los divisores.
    """

    div = []
    for i in range(1, x + 1):
        if x % i == 0:
            div.append(i)
    return div
divisors(124)
#RESPUESTA
[1, 2, 4, 31, 62, 124]
#EJERCICIO 2: Crea una función que dados dos números reales por parámetro, devuelve el mayor.

def higher(a, b):
    """
    Función que devuelve el mayor de dos
    números.

    Args:
        a (float)
        b (float)
    
    Return:
        devuelve a o b en función de cual sea mayor.
    """

    if a > b:
        return a
    elif b > a:
        return b
    else:
        print("Ambos números son iguales.")
        return -1
higher(9,9)
#RESPUESTA
Ambos números son iguales.
-1
#EJERCICIO 3: Crea una función que dado un número devuelva su valor absoluto. Recuerda,

def absolut(x):
    """
    Función que devuelve el valor absoluto de x.

    Args:
        x (float)
    
    Return:
        x o -x (valor absoluto de x).
    """

    if x < 0:
        return (- x)
    else:
        return x
   
absolut(-6)

#RESPUESTA
6
#EJERCICIO 4: Crea una función que devuelva True si el caracter introducido por parámetro se trata de una vocal y False
# en caso contrario.

def vowels(n):
    """
    Función que devuelve si n es vocal o no.

    Args:
        n ("char")

    Return:
        vowel (bool): True si es vocal.
                    False si no es vocal.
    """
    if n == "a" or n == "e" or n == "i" or n == "o" or n == "u":
        vowel = True
    else:
        vowel = False
    return vowel
vowels("6")

#RESPUESTA
False
#EJERCICIO 5: Crea una función que devuelva el MCD (máximo común divisor) de 2 números proporcionados por parámetro.
#PISTA: Aprovecha la función que calcula el mayor entre dos números dados. También necesitarás una función
#que calcula el menor entre dos números dados.

def mcd(a, b):
    """
    Función que devuelve el MCD de a y b
    utilizando el algoritmo de Euclides.

    Args:
        a (int)
        b (int)
    Return:
        MDC (int)
    """
    if higher(a, b) == a:
        while a % b != 0:
            c = a
            a = b
            b = c % b
        return b
    elif higher(a, b) == b:
        while b % a != 0:
            c = b
            b = a
            a = c % a
        return a
mcd(273, 665)

#RESPUESTA
7
#EJERCICIO 6: Crea una función que devuelva el MCM (mínimo común múltiplo) de 2 números proporcionados por
#parámetro.
#PISTA: Aprovecha la función que calcula el MCD de dos números del ejercicio anterior y la función que
#calcula el valor absoluto de un número.

def mcm(a, b):
    """
    Función que calcula el MCM de dos números
    utiizando el método (a * b) / MCD.

    Args:
        a (int)
        b (int)
    Return:
        MCM (int)
    """
    return (a * b) / mcd(a, b)
mcm(72, 50)

#RESPUESTA
1800.0
#EJERCICIO 7: Crea una función que dada una palabra devuelva si es palíndroma.

def palindrome(word):
    """
    Función que comprueba si una palabra es palíndroma.

    Args:
        word (string): palabra a comprobar.

    Return:
        True or False
    """
    if word.lower() == word.lower()[::-1]:
        return True
    else:
        return False
palindrome("Ana")

#RESPUESTA
True
#EJERCICIO 8: Crea una función que dado un color en hexadecimal devuelva una lista de 3 posiciones, cada una de ellas
#correspondiente al valor R, G o B en este orden. Los valores de RGB varían entre 0 y 255.

def colors(hexa_color):
    """
    Función que dado un color en formato: #00FFAA
    devuelva una lista con los valores decimales
    RGB.
    
    Args:
        hexa_color (string): color en formato #00FFAA
    
    Return:
        rgb (list): lista con los valores decimales RGB.
    """

    if len(hexa_color) != 7:
        print("El formato del color no es válido.")
    
    else:
        #Con lo siguiente transformo hexadecimal a decimal con el int(x, 16).
        rgb = [int(hexa_color[1:3], 16), int(hexa_color[3:5], 16), int(hexa_color[5:7], 16)]
    return rgb
colors("#FF0000")

#RESPUESTA
[255, 0, 0]
#EJERCICIO 9: Crea una función que dada una lista de palabras por parámetro, devuelva un diccionario que contenga
#cuántas son de longitud par y cuántas de longitud impar.

def even(words):
    """
    Función que indica cuantas palabras 
    de una lista son pares y cuantas impares
    y lo devuelve en forma de diccionario.

    Args:
        words (list): lista de palabras.
    
    Return:
        even_odd (dic): diccionario pares e 
        impares
    """

    even_odd = {
                "even" : 0,
                "odd" : 0
                }
    
    for word in words:
        if len(word) % 2 == 0:
            even_odd["even"] += 1
        else:
            even_odd["odd"] += 1
    return even_odd
even(["basura", "comida", "albondiga", "hola", "adios"])

#RESPUESTA
{'even': 3, 'odd': 2}
#EJERCICIO 10: Crea una función que dado un string por parámetro cuente cuántas veces sale cada caracter en dicho string
# y devuelva toda esa información en un diccionario.

def letter_counter(sentence):
    """
    Función que cuenta las apariciones de cada uno
    de los carácteres en sentence.

    Args:
        sentence (str): string a contar.
    
    Return:
        counter (dic): diccionario con todo contado.
    """
    counted = []
    counter = {}
    sentence = sentence.lower()
    for i in sentence:
        if i not in counted:
            counter[i.upper()] = (sentence.count(i))
            counted.append(i)
    return counter
letter_counter("aqui hace un frio brutal pero en la playa hace muy buen día")
#RESPUESTA
{' ': 12,
 'A': 8,
 'B': 2,
 'C': 2,
 'D': 1,
 'E': 5,
 'F': 1,
 'H': 2,
 'I': 2,
 'L': 3,
 'M': 1,
 'N': 3,
 'O': 2,
 'P': 2,
 'Q': 1,
 'R': 3,
 'T': 1,
 'U': 5,
 'Y': 2,
 'Í': 1}

Last updated