Funções em Python

Até aqui vimos como criar programas simples em Python. Em todos esses programas, salvamos os resultados das computações em variáveis ou então imprimimos os resultados desejados. Entretanto, existem situações nas quais uma dada porção do nosso programa será utilizada múltiplas vezes, em diferentes partes do programa, ou até mesmo por outros programas.

Imagine, por exemplo, que desejemos criar um programa para exibir a lista dos funcionários de uma empresa, ordenada por ordem alfabética, depois por idade, depois por salário. Nesse caso, temos uma tarefa (ordenar uma lista) que será executada várias vezes (primeiro para ordenar os funcionários por nome, depois por idade, e depois por salário). Em casos como esse, é conveniente que se tenha um procedimento que ordena uma lista de acordo com algum critério. Assim, esse procedimento pode ser aplicado várias vezes sem que tenhamos que repetir o mesmo código em várias partes do programa. Em outras palavras, precisamos de um procedimento que seja reusável em várias partes de nosso programa.

Uma das principais formas de se criar componentes reusáveis em Python (em em outras linguagens de programação também) são as chamadas funções. Uma função é basicamente um trecho de código (um procedimento, um algoritmo) que pode ser usado várias vezes.

Apesar de só estarmos falando sobre funções agora, nós já usamos funções várias vezes nas seções anteriores. Por exemplo, quando fazemos x = abs(y) estamos usando a função abs() da biblioteca padrão Python para calcular o valor absoluto de y e armazená-lo em x. Agora aprenderemos a criar e usar nossas próprias funções em Python.

Funções em Python são definidas por meio da seguinte sintaxe:

def nomedafuncao(parametro1, parametro2, ...):
    corpodafuncao

Os exemplos abaixo ilustram melhor a criação de funções.

# Exemplo (bem simples) de função em Python.
def f(n): (1)
    print("O valor do parâmetro é ", n) (2)

f(10) (3)
O valor do parâmetro é 10
1 Nesta linha, estamos declarando uma função f que recebe um parâmetro n.
2 O corpo da função consiste de apenas um comando, o print.
3 Nesta linha, estamos invocando (chamando) a função f() passando o número 10 como parâmetro.

Em vez de imprimir o parâmetro, podemos simplesmente retorná-lo, como abaixo:

# Exemplo de função que retorna um valor.
def f(n):
    return n (1)

resultado = f(10)
print("O valor do parâmetro é {}".format(resultado))
O valor do parâmetro é 10
1 O comando return retorna um valor. Este valor deve ser salvo em alguma variável para ser usado depois, como fizemos no exemplo acima.

A função acima ilustra o uso do comando return, mas ela não faz nada muito útil. Porém, não se engane: este recurso é muito útil e muito utilizado. Poderíamos, por exemplo, realizar alguma computação com o parâmetro e retornar o resultado desta computação. Vejamos um exemplo.

# Outro exemplo de função que retorna um valor.
def eleva_ao_quadrado(n):
    return n ** 2

print("O número {} elevado ao quatrado é {}".format(10, eleva_ao_quadrado(10)))
O número 10 elevado ao quatrado é 100

Funções em Python podem realizar computações tão complicadas quanto desejarmos. Elas são uma ferramenta poderosa de abstração em programação.

Funções em Python podem retornar mais de um valor:

# Exemplo de função que retorna mais de um valor.
def quociente_resto(x, y):
    quociente = x // y
    resto = x % y
    return (quociente, resto)

print("Quociente e resto: ", quociente_resto(9, 4))
Quociente e resto:  (2, 1)

O exemplo acima, retirado do curso de Python no Edx, mostra um uso interessante de tuplas: o retorno de mais de um valor em uma única chamada de função. Em geral, quando desejamos retornar mais de um valor em uma função, retornarmos uma tupla com os valores desejados. Tenha isso em mente porque essa técnica é bastante usada. E não se preocupe se você não entende o que é uma tupla. Cobriremos este tópico em breve.

Funções anônimas (funções lambda)

Para finalizar essa seção, trateremos de um tópico um pouco mais avançado: funções anônimas, funções lambda, ou funções de alta ordem em Python.

A palavra-chave lambda em Python nos permite criar funções anônimas. Este tipo de função é útil quando desejamos passar uma função simples como argumento para outra função.

A função map aplica uma função a um conjunto de valores. No exemplo abaixo, mostraremos como aplicar uma outra função (eleva_ao_quadrado) a todos os elementos de uma lista. Retornaremos uma nova lista contendo cada número da lista de entrada elevado ao quadrado.

def eleva_ao_quadrado(n):
    return n ** 2

# Função map sem o uso de função lambda.
print(list(map(eleva_ao_quadrado, range(5))))
[0, 1, 4, 9, 16]

Perceba que a função potencia é uma função muito simples, cujo único objetivo é ser passada como parâmetro para a função map. Podemos alcançar o mesmo resultado do código acima de forma mais concisa se usarmos uma função lambda.

# Função map com função lambda.
print(list(map(lambda x: x ** 2, range(5))))
[0, 1, 4, 9, 16]

O conhecimento de como criar funções em Python fará nossos exercícios ficarem muito mais interessantes. A partir deste momento, a maioria deles envolverá a criação de uma função para desempenhar uma tarefa específica. Por mais simples que isso possa parecer, como programador, a maior parte do tempo você estará criando funções, então ter prática nisso ajudará muito.

Retomando o que aprendemos na seção anterior, podemos criar uma função para calcular o fatorial de um número. O exemplo abaixo mostra uma função que recebe um número como parâmetro e retorna o fatorial desse número.

# Exemplo mais elaborado de função em Python.
def fatorial(n):
    fat = 1
    while n > 1:
        fat *= n
        n -= 1
    return fat

print("O fatorial de {} é {}".format(6, fatorial(6)))
O fatorial de 6 é 720

Exercícios

  • Escreva uma função que recebe dois parâmetros e imprime o menor dos dois. Se eles forem iguais, imprima que eles são iguais.

Clique para ver a solução
def imprime_menor(a, b):
    if a < b:
      print(a)
    elif a > b:
      print(b)
    else:
      print("Os números são iguais.")

imprime_menor(0, 5)
imprime_menor(10, 3)
imprime_menor(42, 42)
0
3
Os números são iguais.
  • Escreva uma função que recebe um número n como parâmetro e imprime se n é positivo ou negativo.

Clique para ver a solução
def imprime_sinal(n):
    if n < 0:
      print("Negativo")
    else:
      print("Positivo")

imprime_sinal(-1)
imprime_sinal(5)
Negativo
Positivo
  • Escreva uma função para imprimir o valor absoluto de um número.

Clique para ver a solução
def imprime_valor_absoluto(n):
    if n < 0:
      n = -n
    print(n)

imprime_valor_absoluto(-5)
imprime_valor_absoluto(10)
imprime_valor_absoluto(-1)
5
10
1
  • Escreva uma função que recebe dois números (a e b) como parâmetro e retorna True caso a soma dos dois seja maior que um terceiro parâmetro, chamado limite.

Clique para ver a solução
def soma_maior_que_limite(a, b, limite):
    if a + b > limite:
      return True
    else:
      return False

print(soma_maior_que_limite(10, 5, 15))
True

Perceba que a função acima retorna exatamente o resultado da comparação a + b > limite, isto é, se a + b for maior que limite, a função retorna True e caso contrário ela retorna False. Portanto, nossa função poderia ser escrita de forma mais sucinta assim:

def soma_maior_que_limite_sucinta(a, b, limite):
    return a + b > limite

print(soma_maior_que_limite_sucinta(10, 5, 15))
True

Há quem diga que a primeira versão da função é mais legível, mas há também quem prefira a segunda versão. Independentemente da sua preferência, você encontrará códigos parecidos com as duas versões ao longo do seu aprendizado e trabalho com programação, então é importante saber entender esse tipo de código mais conciso.

  • Escreva uma função que recebe dois números (a e b) como parâmetro e retorna a quantidade (0, 1 ou 2) deles que é maior que um terceiro parâmetro, chamado limite.

Clique para ver a solução
def num_parametros_maior_que_limite(a, b, limite):
    if a > limite and b > limite:
      return 2
    elif a > limite or b > limite:
      return 1
    else:
      return 0

print(num_parametros_maior_que_limite(50, 7, 30))
1
  • Escreva uma função que recebe um número como parâmetro e para cada número menor que o parâmetro, a função imprime "Fizz" se o número for múltiplo de três, imprime "Buzz" se o número for múltiplo de cinco, e imprime "FizzBuzz" se o número for múltiplo de três e cinco. Caso o número não seja múltiplo nem de três nem de cinco, ele deve ser impresso. Note que, ao contrário das funções anteriores, sua função não deve retornar nada. Ela precisa simplesmente imprimir o que foi pedido.

Clique para ver a solução
def fizz_buzz(n):
    for num in range(n):
        if num % 3 == 0 and num % 5 == 0:
            print('FizzBuzz')
        elif num % 3 == 0:
            print('Fizz')
        elif num % 5 == 0:
            print('Buzz')
        else:
            print(num)

print(fizz_buzz(16))
FizzBuzz
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
  • Escreva uma função que, dado um número nota representando a nota de um estudante, converte o valor de nota para um conceito (A, B, C, D, E e F).

Clique para ver a solução
def converte_nota_em_conceito(nota):
    if nota >= 90:
      return "A"
    elif nota >= 80:
      return "B"
    elif nota >= 70:
      return "C"
    elif nota >= 60:
      return "D"
    elif nota >= 40:
      return "E"
    else:
      return "F"

print(converte_nota_em_conceito(65))
D

Note que no exemplo acima, como sempre retornamos um valor dentro de cada teste, não precisamos fazer testes como if nota >= 60 and nota ⇐ 69. Se a nota for maior que 90, ela será retornada no primeiro teste. Caso não seja, mas seja maior que 80 (nesse caso, implicitamente ela está entre 80 e 90) ela é retornada no segundo teste, e assim por diante. Se estivéssemos imprimindo a nota dentro da função (ao invés de retorná-la) não poderíamos ter escrito o código dessa forma. Talvez essa não seria a forma que você escreveria essa função (e há meritos na outra forma, que é mais explicita), mas é importante entender esse tipo de código. Programação não é só escrever código, entender código dos outros é extremamente importante também.

  • Escreva uma função que recebe como entrada uma lista de números e retorna True se um número passado como parâmetro está presente na lista.

Clique para ver a solução
def pesquisa_elemento1(numeros, numero_procurado):
    for numero in numeros:
      if numero == numero_procurado:
          return True
    return False

print(pesquisa_elemento1([1, 10, 20, 30, 50, 100], 30))
True

A função acima nada mais é que uma pesquisa linear na lista de entrada. Em outras palavras, percorremos a lista linearmente, elemento por elemento, e verificamos se cada o elemento corrente é o que estamos procurando. Caso seja, retornamos True. Caso o laço for termine e o elemento não tenha sido encontrado, retornamos False, pois percorremos toda a lista e não encontramos o elemento procurado.

Na função acima, escolhemos percorrer a lista usando um for que percorre cada elemento da lista. Poderíamos também tê-la escrito usando um for que percorre cada índice da lista, como abaixo:

def pesquisa_elemento2(numeros, numero_procurado):
    for indice in range(len(numeros)):
      if numeros[indice] == numero_procurado:
          return True
    return False

print(pesquisa_elemento2([1, 10, 20, 30, 50, 100], 30))
True

Como mencionamos acima, a função pesquisa_elemento nada mais é que uma pesquisa linear na lista de números de entrada. Como esse tipo de pesquisa é usada muito frequentemente, Python disponibiliza um mecanismo built-in (embutido na linguagem) para realizar esse tipo de pesquisa. Vejamos um exemplo:

def pesquisa_elemento3(numeros, numero_procurado):
    return numero_procurado in numeros

print(pesquisa_elemento3([1, 10, 20, 30, 50, 100], 30))
True

Note que o código acima usa o in para verificar se o número procurado está na lista de números recebida como entrada. Neste momento, você pode estar se perguntando qual é a diferença do in usado aqui para o in usado no for na função pesquisa_elemento1. Ocorre que, quando o in é usado juntamente com um for, como na função pesquisa_elemento1, ele é usado para percorrer uma lista de elementos um a um.

Mas, como vimos na função pesquisa_elemento3, o operador in também pode ser usado para checar se um elemento está em uma lista (ou em outra estrutura de dados).

É importante fazer essa distinção de uso do in, principalmente porque, como você verá por você mesmo, ele é muito usado no dia a dia.

  • Escreva uma função que recebe como entrada uma lista ordenada de números e retorna o índice do primeiro elemento maior que um elemento limite. Se nenhum elemento da lista for maior que o limite desejado, retorne o valor -1.

Clique para ver a solução
def retorna_primeiro_maior(numeros, limite):
    i = 0
    while i < len(numeros):
      if numeros[i] > limite:
          return i
    return -1

print(retorna_primeiro_maior([1, 10, 20, 30, 50, 100], 10))
print(retorna_primeiro_maior([1, 10, 20, 30, 50, 100], 200))
2
-1

Desafios

  • Escreva uma função que recebe como entrada um número inteiro positivo n e retorne a soma de todos os inteiros positivos menores ou iguais a n.

  • Escreva uma função que recebe como entrada um número ano e retorna True caso ano seja bissexto. Caso contrário, retorne False.

  • Escreva uma função que recebe como entrada um número n e imprime todas as potências de 2 menores ou iguais a n.

  • Escreva uma função que recebe como entrada um número inteiro positivo n e imprime a representação binária desse número.