Funções em Python


Introdução

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. Nessas situações, precisamos ser capazes de criar um pequeno trecho de código que seja facilmente reusável. Funções são um dos mecanismos da linguagem que nos permitem criar código reusável.

Nesta seção aprenderemos o básico sobre funções, e nas próximas seções iremos praticar bastante e aprimorar nosso uso de funções nas mais diversas situações. Mais tarde no curso cobriremos um conteúdo mais avançado sobre funções, mas é importante introduzirmos o uso de funções o mais cedo possível em nosso aprendizado, pois funções são um recurso essencial em programação.

Como criar funções em Python

Uma das principais formas de se criar componentes reusáveis em Python (e em outras linguagens de programação também) são as chamadas funções.

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.

def f():
    print("Olá!")

f()
Olá!

Note os seguintes aspectos sobre o código acima:

  • No trecho def f(), estamos declarando uma função f que não recebe nenhum parâmetro.
  • O corpo da função consiste de apenas um comando, o print.

Funções também podem receber parâmetros, como mostrado abaixo.

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

f(10)
O valor do parâmetro é 10

Note que para invocar (chamar) a função passando o número 10 como parâmetro, fazemos f(10).

⚠️ CUIDADO

Lembre-se sempre de invocar as funções que você criar. Caso contrário, elas não serão executadas! Por exemplo, se não tivéssemos a chamada de função f(10) no exemplo acima, nada teria sido impresso na tela, pois a função não teria sido executada. Esquecer de chamar uma função é um erro muito comum, principalmente quando se está começando em programação. Portanto, tenha sempre isso em mente quando seu programa não imprimir ou retornar algo que você está esperando. Pode ser que você tenha simplesmente esquecido de invocar uma função ou outra.

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

resultado = f(10)
print("O valor do parâmetro é", resultado)
O valor do parâmetro é 10

O comando return retorna um valor que pode ser salvo em alguma variável para ser usado depois. Esse comando é um recurso muito útil e versátil. Podemos, por exemplo, realizar alguma computação com um 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 * n

print(eleva_ao_quadrado(10))
100

Perceba que elevamos n ao quadrado simplesmente fazendo n * n. Outra maneira de obter o mesmo resultado seria usando o operador de exponenciação do Python, fazendo n ** 2. Usaremos esse operador nos próximos exemplos.

Composição de funções

Python nos permite fazer composição de funções, ou seja, podemos obter o resultado de uma função e passá-lo como parâmetro para outra função, como ilustrado abaixo.

def eleva_ao_quadrado(n):
    return n ** 2

def eleva_ao_cubo(n):
    return n ** 3

def eleva_a_6(n):
    return eleva_ao_quadrado(eleva_ao_cubo(2))

print(eleva_a_6(2))
64

No exemplo acima, a função eleva_ao_cubo(2) retornará como resultado 8, e o valor 8 será passado como parâmetro para a função eleva_ao_quadrado, que então retornará 64.

Obviamente, poderíamos ter definido a função de forma mais simples e elevado o número a 6 dentro de uma única função, mas nosso intuito com o exemplo acima é mostrar que funções podem ser compostas de forma a obter resultados mais complexos a partir de funções simples.

Variáveis locais

Até este momento, realizamos computações muito simples nas funções que criamos. Quando precisamos realizar operações mais complexas, podemos declarar variáveis dentro de funções e realizar as mais diversas computações com essas variáveis, como ilustrado no exemplo a seguir.

def area_triangulo(base, altura):
    area = (base * altura) / 2
    return area

print(area_triangulo(4, 6))
12
📌 NOTA

Variáveis declaradas dentro de uma função só são visíveis dentro da função. No exemplo acima, se tentássemos acessar a variável area fora da função area_triangulo, obteríamos um erro.

Além disso, variáveis locais que possuem o mesmo nome que outras variáveis são distintas. Vejamos um exemplo.

area = 0

def area_triangulo(base, altura):
    area = (base * altura) / 2
    return area

print(area_triangulo(4, 6))
print(area)
12
0

No exemplo acima, temos uma variável area externa à função area_triangulo e uma variável area dentro da função. Essas duas variáveis são distintas, apesar de possuírem o mesmo nome.

Para entender isso, precisamos introduzir a noção de escopo. O escopo de uma função é como se fosse um espaço pertencente àquela função somente. Variáveis declaradas dentro da função não são visíveis no escopo externo. E se uma variável local possui o mesmo nome de uma variável declarada fora do escopo da função, o nome da variável local sobrescreve o nome da variável externa dentro do escopo da função. Modificações no conteúdo da variável local dentro da função afetam somente a variável local, ainda que ela tenha o mesmo nome de uma variável externa à função. Por exemplo, quando modificamos a variável area dentro da função, não estamos modificando a variável externa, mas somente a variável local à função (a variável externa permanece com o valor 0, conforme ilustrado no exemplo).

Se quisermos modificar uma variável externa a uma função, precisamos indicar explicitamente que desejamos fazer isso. O recurso que nos permite modificar variáveis externas ao escopo de uma função é a palavra-chave global. Vejamos um exemplo.

area = 0

def area_triangulo(base, altura):
    global area = (base * altura) / 2
    return area

print(area_triangulo(4, 6))
print(area)
12
12

Como declaramos area dentro da função como global, estamos na verdade nos referindo à variável area declarada fora da função. Com isso, ao modificarmos area dentro da função, estamos de fato alterando a variável externa.

📌 NOTA

Estamos abordando este tópico aqui para que você saiba que o recurso global existe. Mas, sempre que possível, evite usar esse recurso em seus programas, pois o uso de variáveis globais torna o entendimento de funções (e de programas como um todo) muito mais difícil.

Usando docstrings para documentar funções

Python possui uma funcionalidade chamada “documentation strings” (ou simplesmente “docstrings”) usada para documentação de de funções. Este é o formato geral de utilização de docstrings:

def foo(arg1, arg2, ...):
    """
    Computa alguma coisa e retorna outra coisa.

    arg1: descrição sobre arg1
    arg1: descrição sobre arg1
    """

    return something

O exemplo acima é bastante genérico, mas ilustra os principais pontos sobre docstrings:

  • A docstring de uma função deve vir na linha abaixo da declaração da função.
  • Docstrings são delimitadas por aspas triplas: “““docstring…”””
  • Uma docstring deve descrever o que a função faz e o que ela retorna.
  • É boa prática incluir explicações sobre cada um dos parâmetros da função, incluindo o tipo de cada parâmetro.

Vejamos um exemplo mais concreto:

def area_triangulo(base, altura):
    """
    Retorna um float representando a área de um triângulo, dadas a sua base e altura.

    base: tamanho da base do triângulo (float)
    altura: tamanho da altura do triângulo (float)
    """
    area = (base * altura) / 2
    return area

Podemos acessar a docstring da função area usando o atributo __doc__ (observe os dois underscores) da função. Lembre-se de que o Python trata tudo como um objeto, e isso inclui funções. Aprenderemos mais sobre objetos nos capítulos seguintes.

Se você já usou help() em Python, então já viu o uso de docstrings! O que a função help faz é simplesmente buscar o atributo __doc__ da função e exibi-lo de maneira organizada para você. Você pode experimentar na função acima: basta incluir help(area) em seu programa. Lembre-se de pressionar a tecla “q” para sair da ajuda.

A partir deste ponto adotaremos a prática de incluir docstrings para as funções mais complexas que criarmos. Essa é uma prática fortemente recomendada. Lembre-se que seu código será lido por outras pessoas, ou por você mesmo no futuro, e ter uma descrição das partes complexas do código facilita muito o entendimento.

Conclusão

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

Se você chegou até aqui, parabéns! Esta seção é um marco importante no curso porque a partir de agora começaremos a desenvolver programas mais interessantes, sempre fazendo uso de funções para criar trechos de código mais complexos e reusáveis.

Exercícios

  1. Escreva uma função que recebe dois números como parâmetro e retorna a média dos números.
Clique para ver a solução
def media(a, b):
    return (a + b) / 2

media(0, 5)
media(2, 4)
2.5
3.0
  1. Escreva uma função que recebe um número n de ponto flutuante como parâmetro e retorna a conversão de n para inteiro.
Clique para ver a solução
def converte_para_int(n):
    return int(n)

converte_para_int(3.33)
converte_para_int(4.2)
converte_para_int(5.9)
3
4
5
  1. Escreva uma função que recebe um número inteiro graus_celsius indicando a temperatura em graus Celsius e retorna a temperatura equivalente em Fahrenheit.
Clique para ver a solução
def celsius_para_fahrenheit(graus_celsius):
    return (graus_celsius * 9 / 5) + 32

celsius_para_fahrenheit(25)
celsius_para_fahrenheit(0)
77.0
32.0
  1. Escreva uma função que recebe um número inteiro graus_fahrenheit indicando a temperatura em graus Fahrenheit e retorna a temperatura equivalente em Celsius.
Clique para ver a solução
def fahrenheit_para_celsius(graus_fahrenheit):
    return (graus_fahrenheit - 32) * 5 / 9

fahrenheit_para_celsius(54)
fahrenheit_para_celsius(100)
12.222222222222221
37.77777777777778