Aula7.png

1. Funções

1.1. Motivação

Imagine que você receba um código de alguém. Nele, o programa deverá receber um número e dizer se ele é par, se é múltiplo de 3 e se é primo. Considere as duas implementações abaixo. Qual delas é mais fácil de entender?

Figura1.png

Figura 1: Comparação entre dois trechos de código de mesma semântica, mas sintaxes diferentes, um estando bem modularizado e o outro não

O código da esquerda tem algumas vantagens. Entre elas, podemos listar:

  • É bem mais fácil de entender
  • Caso o programa apresente algum problema, é mais fácil consertar
  • Divide as tarefas do programa em tarefas menores (subtarefas), mais fáceis de resolver. Essas subtarefas são chamadas de funções.

Já utilizamos diversas funções ao longo do curso, como print() e input(), além das diversas funções da biblioteca math, como sqrt() e factorial().

Funções são sequências de instruções que podem ser utilizadas para tornar códigos mais legíveis e organizados, e o melhor: podem ser utilizadas sem que seja necessário entender como elas fazem o que fazem. Você, por exemplo, não precisa saber como a função sqrt() calcula a raiz quadrada de um número, só precisa saber utilizá-la. Além disso, se um código apresentar erros e ele estiver modularizado em funções, fica mais simples de depurar, ou seja, testar o funcionamento de cada parte do programa e até identificar o erro.

Funcoes1resized.png

Figura 2: Exemplo de um programa bem modularizado, com o uso de função

Funcoes2resized.png

Figura 3: O mesmo programa da imagem 2 sem o uso da função,
as chaves demonstram como um conjunto de linhas poderia
ser substituído por apenas uma linha se implementássemos a função

Agora que já vimos os benefícios do uso de funções, aprenderemos a criá-las!


1.2. Definição e Regras

Para definirmos uma função, utilizamos a palavra reservada def. Logo após o def, escrevemos o nome da função e colocamos seus parâmetros entre parênteses (trataremos de parâmetros logo à frente). Por fim, encerramos a linha com dois pontos, :. Observe a criação de uma função simples que imprime "Olá!":

In [ ]:
def diz_ola():
    print("Olá!")

Observe que ao executar a celula acima, o print() não é executado, pois a palavra chave def apenas define o trecho de código.

Para utilizarmos a função, basta escrevermos seu nome seguido dos parenteses:

In [ ]:
diz_ola()

Repare que o print dentro da função possui uma tabulação, ou 4 espaços, assim como um if else. Qualquer coisa que seja colocada fora dessa regra não será considerada como parte da função.

A forma geral de definição de uma função é:

def <nome> ( <parametros> ):
    <comandos da função>

Mas o que aconteceria se usássemos uma palavra reservada, por exemplo input, como nome da nossa função?

In [ ]:
def input():
    print("A função funciona!")
In [ ]:
input()

Perceba que podemos redefinir funções que já existem, embora não seja uma boa prática de programação no momento. Este é um conceito mais avançado que não será abordado no curso. Por agora, é preferível criar novas funções do que sobrescrever as já existentes.

Exercício 1

Crie uma função que imprima um número lido do teclado. Tanto a leitura do número quanto sua impressão devem ser feitas dentro da função!

In [ ]:
#Defina sua função aqui
In [ ]:
#Chame sua função aqui

Veremos exemplos mais complexos a partir de agora, falando de parâmetros.


1.3. Parâmetros e Argumentos

Funções como a diz_ola são muito simples e parecem até um tanto desnecessárias, portanto veremos funções mais complexas, que possuem ao menos um parâmetro.

Parâmetro é a variável que recebe um valor em uma função, enquanto argumento é o valor que você passa para a função. Por exemplo: quando você quer saber a raiz quadrada de um número, você chama a função sqrt(). Essa função tem apenas um parâmetro e, portanto, só necessita de um número como argumento.

Funcoes3resized.png

Figura 4: Demonstração da diferença entre argumentos e parâmetros em um código

Veja no exemplo a seguir como fazer suas funções receberem parâmetros. Nossa função receberá um número e imprimirá o resultado de sua multiplicação por 5:

In [ ]:
#Definimos nossa função aqui
def multiplica_por_5(num):
    num_multiplicado = num * 5
    print(num_multiplicado)
In [ ]:
#Chamamos nossa função aqui
x = 40
multiplica_por_5(x)

Nossas funções podem ter multiplos parâmetros! Basta separá-los por virgulas, como é demonstrado em nosso próximo exemplo. Nele, recebemos dois números como parâmetros e imprimimos o maior dos dois:

In [ ]:
def imprime_maior(numA, numB):
    if numA > numB:
        print(numA)
    else:
        print(numB)
In [ ]:
imprime_maior(10, 40)

Repare que os nomes dos argumentos não precisam ser iguais aos nomes definidos nos parâmetros da função. Por exemplo: na função multiplica_por_5, o nome do parâmetro definido na função é "num", mas quando chamamos a função, mandamos a variável x como argumento, e lá, o valor da variável x é atribuido à num.

Exercício 2

Agora que sabemos criar funções com parâmetros, crie uma função que, dado dois catetos de um triângulo retângulo, imprima sua hipotenusa.

In [ ]:
cateto1 = int(input())
cateto2 = int(input())

#sua função deve ser criada a partir daqui
In [ ]:
#teste sua função aqui

Mas e se não quisermos que nossa função imprima o resultado, e sim salve esse resultado para uma variável? Responderemos essa pergunta com o comando return a seguir!


1.4. Funções com retorno

Nem sempre queremos que as funções que criamos imprimam algo. As vezes só queremos que elas calculem algo e salvem isso em uma variável. Podemos fazer isso com o comando return. No nosso ultimo exemplo, nossa função imprime_maior sempre imprimia o maior número. Agora criaremos uma função parecida, que informa o maior de dois números:

In [ ]:
#Definimos a função aqui
def maior(numA, numB):
    if numA > numB:
        return numA
    else:
        return numB
In [ ]:
#Chamamos a função aqui
var = maior(40, 320)
var

Exercício 3

Modifique a função que calcula a hipotenusa nas celulas abaixo. Dessa vez, em vez de imprimir a hipotenusa na função, retorne seu valor para uma variável.

In [ ]:
#modifique a função aqui
In [ ]:
#teste sua função aqui

1.5. Funções chamando outras funções

Podemos também utilizar o retorno de uma função como argumento de outra. Essa prática é muito útil em determinadas situações, como no exemplo a seguir: Imagine que você precisa descobrir o maior entre 4 números! Apresentaremos duas soluções para o problema, sendo a segunda solução mais recomendada. Lembre-se de que a função maior(a, b) já foi definida acima, então não é preciso defini-la novamente.

In [ ]:
a = 20
b = 30
c = 2
d = 70

#Aqui criamos duas variáveis para salvar o maior valor entre A e B e entre C e D
#e chamamos a função maior para nos retornar qual é o maior
maior_entre_A_e_B = maior(a, b)
maior_entre_C_e_D = maior(c, d)

#Após descobrirmos os maiores entre A e B e entre C e D, descobrimos o maior entre
#esses dois
maior_total = maior(maior_entre_A_e_B, maior_entre_C_e_D)
print(maior_total)
In [ ]:
#Aqui o retorno das chamadas de função "maior(a, b)" e "maior(c, d)" servem
#como argumento para a chamada de função abaixo
maior_total = maior(maior(a,b), maior(c, d)) 
print(maior_total)

Além disso, funções podem chamar outras funções dentro delas. Imagine que não podemos utilizar a função tan(), mas precisamos calcular a tangente de um angulo. Podemos criar uma nova função tan que funcionará da mesma forma:

In [ ]:
import math
In [ ]:
#Aqui o resultado do seno de x e do cosseno de x será calculado
#e este valor calculado é retornado
def tg(x):
    return (math.sin(x)/math.cos(x))
In [ ]:
resposta = tg(math.radians(45))
print(resposta)

1.6. Fluxo de execução de um programa com funções

Vamos acompanhar o exemplo a seguir e entender seu fluxo de execução.

In [ ]:
#Definimos aqui a função que retorna o maior número
def maior(a, b):
    if a > b:
        return a
    else:
        return b
    
#Definimos aqui a função que diz se o número é primo ou não
def eh_primo(x):
    y = 2
    while(y != x):
        if x % y == 0:
            return False
        y += 1
    return True

#O código começa aqui!
a = int(input())
b = int(input())

maior_num = maior(a, b)

print(maior_num, "é primo?")

resposta = eh_primo(maior_num)

if resposta:
    print("Sim!")
else:
    print("Não!")

1.6.1. A função main

Na maioria das linguagens de programação existe uma função chamada main (em tradução literal, função principal), e é nessa função que todas as outras funções são chamadas. Em Python a declaração da main não é obrigatória, entretanto é possível utilizar tal recurso, e seu uso é bem visto (uma vez que torna o código mais organizado).

In [ ]:
# Código sem uso da função main:

def bhaskhara(a, b, c):
    delta = b ** 2 - 4 * a * c
    
    if delta < 0:
        return None, None
    
    x1 = b + delta ** (1/2) / (2 * a)
    x2 = b - delta ** (1/2) / (2 * a)
    
    return x1, x2
    
a = int(input("Insira 'A':"))
b = int(input("Insira 'B':"))
c = int(input("Insira 'C':"))

x1, x2 = bhaskhara(a, b, c)
print(f"x1 = {x1}; x2 = {x2}")
In [ ]:
# Código com uso da função main (método 1):
def bhaskhara(a, b, c):
    delta = b ** 2 - 4 * a * c
    
    if delta < 0:
        return None, None
    
    x1 = b + delta ** (1/2) / (2 * a)
    x2 = b - delta ** (1/2) / (2 * a)
    
    return x1, x2
    
def main():
    a = int(input("Insira 'A':"))
    b = int(input("Insira 'B':"))
    c = int(input("Insira 'C':"))

    x1, x2 = bhaskhara(a, b, c)
    print(f"x1 = {x1}; x2 = {x2}")

main()
In [ ]:
# Código com uso da função main (método 2 / mais elegante):

def bhaskhara(a, b, c):
    delta = b ** 2 - 4 * a * c
    
    if delta < 0:
        return None, None
    
    x1 = b + delta ** (1/2) / (2 * a)
    x2 = b - delta ** (1/2) / (2 * a)
    
    return x1, x2
    
def main():
    a = int(input("Insira 'A':"))
    b = int(input("Insira 'B':"))
    c = int(input("Insira 'C':"))

    x1, x2 = bhaskhara(a, b, c)
    print(f"x1 = {x1}; x2 = {x2}")

if __name__ == "__main__":
    main()

Algumas dicas interessantes quanto ao uso da main:

  • É interessante deixar a main como a última ou primeira função de seu arquivo, isso facilita a leitura.
  • Em programas que utilizam separação em arquivos é usual a main ter um arquivo próprio, normalmente chamado main.py.
  • Em outras linguagens de programação, como Java e C, o uso da main é obrigatório.
  • Mesmo que não exista uso da main no seu código é sempre interessante que funções não sejam declaradas em meio às chamadas de outras funções e declarações de variáveis (ver exemplo abaixo)
In [ ]:
# Esse código é ruim:

a = int(input("Insira 'A':"))
b = int(input("Insira 'B':"))
c = int(input("Insira 'C':"))

# A função está sendo declarada dentro do fluxo de execução da parte
# principal do código, isso pode tornar a leitura confusa,
# principalmente em códigos grandes (onde, nesse caso, existiriam
# diversas funções espalhadas pelo arquivo).

def bhaskhara(a, b, c):
    delta = b ** 2 - 4 * a * c
    
    if delta < 0:
        return None, None
    
    x1 = b + delta ** (1/2) / (2 * a)
    x2 = b - delta ** (1/2) / (2 * a)
    
    return x1, x2

x1, x2 = bhaskhara(a, b, c)
print(f"x1 = {x1}; x2 = {x2}")

1.7. Escopo de variáveis

O que aconteceria caso você criasse uma variável dentro de uma função e tentasse imprimi-la fora dela? Execute o código a seguir e veja o que acontece.

In [ ]:
#Definimos nossa função aqui
def funcao1():
    dentro = 40
    print(dentro)
In [ ]:
#Tentamos imprimir a variável "dentro" aqui
print(dentro)

Como visto acima, um erro ocorre, informando que a variável dentro não está definida. Claro que ela está definida e funciona muito bem dentro do escopo da função, mas ao tentar utiliza-la fora desse escopo, recebemos um erro. É muito importante prestarmos atenção no escopo dessas funções para que esse tipo de erro não ocorra.


1.8. Passagem por cópia e por referência

Dependendo do tipo de dado que for passado como argumento da função, precisamos tomar cuidado ao altera-lo. Alguns tipos de dados, como int, float, bool, str não são alterados fora da função, e portanto, precisam ser retornados.

Chamamos isso de passagem por cópia!

Observe o exemplo a seguir:

In [ ]:
#Definimos aqui uma função que multiplica por 100 um número inteiro
def multiplica_por_100(x):
    x *= 100
    print("O valor de x dentro da função é:", x, end = "\n\n")
    
x = 25
print("O valor de x antes de chamar a função é:", x, end = "\n\n")
multiplica_por_100(x)
print("O valor de x depois de chamar a função é:", x, end = "\n\n")

Porém, alguns tipos de dados, como dicionários e listas (e objetos, que veremos no módulo 2), caso sejam alterados dentro da função, também são alterados fora da função.

Chamamos isso de passagem por referência!

Observe o exemplo abaixo:

In [ ]:
# Definimos aqui uma função que multiplica por 100 todos os números inteiros da lista
def multiplica_lista_por_100(lis):
    for i in range(len(lis)):
        lis[i] *= 100
    print("Os valores da lista dentro da função são:", lis, end = "\n\n")
        
lis = [1, 2, 3, 4, 5]
print("Os valores da lista antes da função são:", lis, end = "\n\n")
multiplica_lista_por_100(lis)
print("Os valores da lista depois da função são:", lis, end = "\n\n")

1.9. Como depurar um programa com funções

Quando temos problemas com códigos que possuem diversas funções, é bem comum verificar se cada uma está funcionando corretamente, isso se chama depurar. Ao testar e verificar que cada script menor está apresentando o resultado esperado, voltamos para a "parte principal" do código, pois sabemos que o problema provavelmente está lá, e não nas funções.

Há três tipos de erros que podem acontecer:

  1. Erros de sintaxe: se referem à estrutura de um programa e as regras que regem essa estrutura. Exemplo: parêntesis que abrem mas não fecham, falta de indentação em local necessário, dois números lado a lado sem operador.
  2. Erros de semântica/execução: ocorre quando o significado do seu programa está incorreto. O código pode estar dentro de todas as regras daquela linguagem mas, ainda assim, não fazer sentido. Exemplo: dividir um número por uma string, dividir zero por algum número ou vice versa, utilização de palavras reservadas pela linguagem em locais indevidos. Esses erros levam a falhas na execução do programa.
  3. Erros de lógica: são mais difíceis de identificar, já que o programa está rodando e aparentemente correto. Acontece quando o código não funciona da maneira esperada, ou seja, a solução dada pelo programador não é a solução certa. Exemplo: uso incorreto de operadores, não colocar um ponto de parada em um loop (isso faria ele rodar infinitamente), operações incorretas.

1.9.1. Como resolver esses problemas?

Há diversos métodos para depurar um programa. O jeito mais fácil é através de IDEs (Ambientes de Desenvolvimento Integrado) que oferecem essa opção, como NetBeans, VisualStudio, PyCharm e outros. No entanto, nem sempre é possível utilizar essas plataformas. Por isso, é necessário ter conhecimento para fazer isso você mesmo.

Primeiramente, ao se deparar com o erro, você deve observar qual tipo está sendo apontado (sintaxe, execução ou lógica - saídas diferentes do esperado). No caso de erro de sintaxe, você deve revisar o seu código, procurando linha por linha o local onde a escrita não esteja de acordo com as regras da linguagem utilizada. Caso haja erro de execução, é necessário que você revise as operações realizadas, para ter certeza de que nenhuma acontece de maneira indevida. Já se o erro for de lógica, você precisa ter uma lista de saídas esperadas, ou seja, resultados que deveriam aparecer no programa e comparar com a saída fornecida. Assim, é possível procurar em que ponto do código existe uma ação incorreta. Em todos esses casos, a primeira coisa que o programador tem que saber são alguns possíveis resultados para aquele programa. A melhor maneira de saber o que está acontecendo com o seu código é imprimir na tela os resultados passo a passo. Inserir condicionais junto com as funções print() também pode ajudar, já que o programa apenas imprimiria caso aquela condição fosse atendida, caso contrário, você sabe que existe um erro (o contrário também é válido).

In [ ]:
# Exemplo de código sem testes de saída de funções:

def total(x, y, z):
    t = x * y * z
    return t

def imposto(x):
    imp = (x * 11) / 100
    return imp

def inss(x):
    i = (x * 8) / 100
    return i

def sindicato(x):
    sind = (x * 5) / 100
    return sind


# Obtendo o salário total:
sal_hora = 15.50 # salario por hora
hora_dia = 8 # horas trabalhadas
dias_mes = 20 # quantidade de dias trabalhados
sal_bruto = total(sal_hora, hora_dia, dias_mes) # salario total sem descontos

# Calculando descontos:
imp = imposto(sal_bruto)
i = inss(sal_bruto)
sind = sindicato(sal_bruto)

# OBS: Salário liquido = salario bruto - descontos
sal_liq = sal_bruto - imp - i - sind

print("O salário líquido é: R${}".format(sal_liq))

# RESULTADO ESPERADO:
# - SALBRUTO = 2480
# - IMP = 272,8
# - I = 198,4
# - SIND = 124
# - SALLIQ = 1884,8
In [ ]:
# O mesmo código com testes de saída de funções:
def total(x, y, z):
    t = x * y * z
    return t

def imposto(x):
    imp = (x * 11) / 100
    return imp

def inss(x):
    i = (x * 8) / 100
    return i

def sindicato(x):
    sind = (x * 5) / 100
    return sind

sal_hora = 15.50 # salario por hora
hora_dia = 8 # horas trabalhadas
dias_mes = 20 #q uantidade de dias trabalhados
sal_bruto = total(sal_hora, hora_dia, dias_mes) # salario total sem descontos

imp = imposto(sal_bruto)
i = inss(sal_bruto)
sind = sindicato(sal_bruto)
sal_liq = sal_bruto - imp - i - sind

# Bateria de testes:
saidas_obtidas = [sal_bruto, imp, i, sind]
saidas_esperadas = [2480, 272.8, 198.4, 124]

for i in range(len(saidas_obtidas)):
    if saidas_obtidas[i] == saidas_esperadas[i]:
        is_ok = "Ok!"
    else: is_ok = "Erro!"    
    print("R${} : {}".format(saidas_obtidas[i], is_ok))

# Exibindo o salário líquido
print("\nO salário líquido é: R${}".format(salLiq))

# RESULTADO ESPERADO:
# - SALBRUTO = 2480
# - IMP = 272,8
# - I = 198,4
# - SIND = 124
# - SALLIQ = 1884,8

Exercício 4

Analise os códigos abaixo e corrija o que for necessário.

In [ ]:
import math

def soma(x,y):
    x + y

def pitagoras(b,c):
    x = b**2
    y = c**2
    a = soma(x,y)
    return a

num1 = input("Digite um número: ") 
num2 = input("Digite outro número: ")
num3 = pitagoras(b,c)


if(num3 > 10):
print("num3 é maior que 10")
else:
print("num3 é menor que 10")


if(type(num3) == 'int'):
    print("num3 é inteiro \nnum3 = ", num3, "é ", type(num3))
else if(type(num3 == 'int')):
    print("num3 não é inteiro \nnum3 = ", num3, "é ", type(num3))
In [ ]:
def soma(num1, num2):
  soma = num1 + num2

def eh_primo:
  soma = soma(num1, num2)
  for i in range(1, soma):
  if(soma % i == 0):
    eh_divisor++
    else:
      continue
  if(eh_divisor != 2):
    print("{} não é primo".format(soma))
  else: 
    print("{} é primo".format(soma))

num1 = 10 
num2 = 3

#OBS: SAÍDA ESPERADA: "13 é primo"

Agora veja o mesmo problema sendo resolvido com o auxílio de um IDE, nesse caso foi utilizado o PyCharm.

In [ ]:
# Execute esta célula para visualizar o vídeo:
from IPython.display import IFrame


display(IFrame("https://www.youtube.com/embed/_hCd39HV0sM", 480, 360))



1.10. O que pode dar errado?

Abaixo listaremos apenas alguns erros possíveis e para cada um, apenas algumas soluções possíveis, lembre-se de buscar ajuda com seus colegas, professores e comunidades on-line caso se depare com um erro não abordado aqui. Cada vez que se deparar com um erro será mais fácil resolvê-lo conforme ganha experiência, por isso é muito importante que sempre pratique.


Erro 1: Chamada incorreta da função:

É comum que esqueçamos um ou mais parâmetros de uma função, ou mesmo coloquemos na ordem errada (nesse segundo caso a situação pode ser ainda pior, pois não é emitido nenhum aviso), devemos sempre prestar muita atenção para não cometer nenhum desses erros.

In [ ]:
def diga_olá(nome, idade):
    return "Olá, sou {} e tenho {} anos".format(nome, idade)

diga_olá(16, "Juvenal")
In [ ]:
# Será emitido o erro "TypeError: diga_olá() missing 1 required positional argument: 'idade'"

diga_olá("Juvenal")

Erro 2: Declaração incorreta da função

É possível esquecer de inserir a indentação da função, ou até mesmo dos dois pontos, conforme o exemplo abaixo:

In [ ]:
def soma(x, y)
return x + y

O caso acima é bem absurdo, mas podemos cometer esse mesmo erro de formas mais críticas (e não seremos notificados pelo terminal, vejamos:

In [ ]:
def soma(lista_de_numeros):
    soma = 0
    for num in lista_de_numeros:
        soma = soma + num
        return soma

2. Tuplas

2.1. O que é uma tupla?

Em aulas anteriores estudamos listas e seu funcionamento. As tuplas são listas imutáveis. E o que isso quer dizer? om listas podemos adicionar ou remover elementos; com tuplas sso é impraticável. Podemos resumir uma tupla como sendo uma lista que tem as seguintes restrições:

  • Não é possível adicionar novos elementos;
  • Não é possível remover elementos existentes;
  • Não é possível alterar os elementos;
  • Não é possível ordenar os elementos.

2.2. Como declarar uma tupla?

Declaramos tuplas da mesma forma que declaramos listas; a diferença é que listas são delimitadas por colchetes [] enquanto tuplas são delimitadas por parêntesis ().

Uma tupla pode ser declarada tanto como tupla = (x, y) quanto como tupla = x, y

Uma tupla de somente um elemento é algo do tipo (x), que pode ser declarada como, t1 = (x) ou t1 = 1,.
Uma tupla vazia também é declarada como t1 = ().


2.3. Uma lista ou uma tupla?

Se você declarar uma tupla e chamar type( < tupla > ), a função nos retorna o tipo da estrutura. Rode o código a seguir.

In [ ]:
tup = ("Carlos", 26, 2, 1999)
type(tup)

Você também pode declarar suas tuplas chamando uma função tuple ( " uma string qualquer " ). Essa forma de declaração nos retorna uma tupla de caracteres.

In [ ]:
tupla_strings = tuple("Olá, sou uma string!")
tupla_strings

2.4. Operações básicas com tuplas

As operações que fazemos com as listas também podem ser utilizadas com tuplas. Considere os exemplos a seguir:

In [ ]:
# Aqui estamos criando uma tupla com os elementos 3 "vamos" 4  e "fugir"
t = (3, "vamos", 4, "fugir")
# Aqui estamos perguntando se 3 está dentro da nossa tupla, se sim retornara True se não retornara False.
3 in t
In [ ]:
# Declaração de tupla
t1 = 2, "chega", 555, "C++"
# Concatenação das tuplas
t2 = t + t1 
# Printando tupla resultante
print(t2)
In [ ]:
# Tupla de somente 1 elemento
t3 = 1, 
# Concatenando essa tupla a ela mesma 5 vezes.
t4 = t3 * 5

print(t4)

Podemos acessar elementos da tupla como acessando elementos de uma lista.

In [ ]:
print(t)

print(t[0])
# Somando o primeiro elemento com o terceiro elemento da tupla.
t5 = t[0] + t[2]

print(t5)

print(t[-1])

# O -1 é o indice do ultimo elemento da tupla, igual para lista.

Podemos fazer uma tupla de listas e também uma lista de tuplas, existe uma função chamada enumerate nativa da python capaz de nos retornar tuplas com os indices e os elementos dos indices da lista.

In [ ]:
l1 = ['a', 'b', 'c', 'd', 'e']
# Criando lista de tuplas
l2 = list(enumerate(l1))
print(l2)

Se você observar verá que as tuplas seguem o padrão (indice, elemento) da lista para qual chamamos o enumerate.

In [ ]:
# Criamos uma tupla de listas
tp = ([1,2,3], [4,5,6])
# Printando o terceiro elemento da primeira posição da tupla
print(tp[0][2])

Outra operação que podemos fazer com elas são comparar se uma tupla é menor, maior ou igual.

In [ ]:
t < t1

Para saber se uma tupla é menor que outra comparamos elemento por elemento, a ideia é, comparar o elemento primario se for menor ja retorna True, caso seja igual ele vai para os elementos seguintes. O mesmo vale para as operações > ou == .

In [ ]:
(1,2,3,5) < (1,2,3,4)
In [ ]:
(1,2,3,4) < (2,3,4,5)
In [ ]:
# Printando tupla recortada do segundo ao terceiro elemento
print(t[1:3])

Também conseguimos usar o for com tuplas, se liga.

In [ ]:
for x in ("a", 1, 2, 3, "b", 4, 5, 6, "c"):
    print(x)

2.5. Por que utilizar uma tupla?

Se uma tupla funciona como uma lista, mas não pode ser alterada ao longo do programa, por que escolher esse tipo de variável? Apesar do seu funcionamento parecido, dizer que tuplas são somente listas imutáveis não está totalmente certo! Usamos isso para deixar o aprendizado dessa estrutura um pouco mais didático.

Você deve usar uma tupla sempre que os dados inseridos forem constantes. Além disso, as tuplas tem como objetivo trabalhar com dados heterogêneos, ou seja, dados de diversos tipos e significados. Por exemplo: se o seu programa tem como objetivo trabalhar com coordenadas geográficas, o uso da tupla garante que esses valores não serão modificados ao longo das operações realizadas. Sem contar que, com elas, podemos agilizar, e muito, a escrita do código.

De forma resumida, as tuplas são mais rápidas e previnem o seu script de alterações indesejadas.


2.5.1. Troca rápida de valores e divisão de tuplas em variáveis

Sem o uso de tuplas, utilizamos três linhas de código para trocar os valores de duas variáveis. Porém, com tuplas, é possível fazer isso em apenas uma linha. Vejamos:

In [ ]:
a = 1
b = 2

# Sem tuplas:
aux = a
a = b
b = aux

a, b
In [ ]:
a = 1
b = 2

# Com tuplas:
a, b = b, a

a, b

Isso ocorre por uma propriedade das tuplas que permite que elas sejam “separadas” em variáveis. Exemplo:

In [ ]:
# Declarando uma tupla:
coordenadas = 1.2, 5.9

# "Separando" a tupla em duas variáveis:
x, y = coordenadas

x, y

2.5.2. Uso de tuplas na entrada e saída de funções:

Como visto acima, as tuplas podem ser divididas em variáveis. Tal propriedade ainda nos permite retornar “vários valores” a partir de uma mesma função.

In [ ]:
import math

# Função que permite encontrar as raízes de uma equação de segundo grau:
def bhaskara(a, b, c):
    delta = b**2 - 4 * a * c
    if delta < 0: return None, None

    return (b + math.sqrt(delta))/(2*a), (b - math.sqrt(delta))/(2*a)

# x1 e x2 receberão as raízes da equação de segundo grau.
x1, x2 = bhaskara(2, 3, 1)

x1, x2

Podemos ainda passar um número indeterminado de valores como argumentos de uma função apenas colocando *args como parâmetro. *args é, na verdade, uma tupla e fará a função receber quantos parâmetros você precisar.

In [ ]:
#Definimos nossa função aqui
def soma_numeros(*args):
    soma = 0
    for x in args:
        soma += x
    
    return soma
In [ ]:
#Chamamos nossa função aqui:
#Tente colocar mais ou menos valores 
soma = soma_numeros(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
soma

Exercício 5

Crie uma função que retorne o maior número entre os parâmetros. Utilize o parâmetro *args para poder colocar quantos números forem necessários!

In [ ]:
# Defina sua função aqui
In [ ]:
# Teste sua função aqui

Agradecemos pela atenção e esperamos que tenham aprendido bem o conteúdo, para que possamos sempre melhorar é de extrema importância que colaborem através de seu feedback, ficaremos ainda mais gratos caso respondam nosso formulário sobre a aula.



2.6. O que pode dar errado?

Abaixo listaremos apenas alguns erros possíveis e para cada um, apenas algumas soluções possíveis, lembre-se de buscar ajuda com seus colegas, professores e comunidades on-line caso se depare com um erro não abordado aqui. Cada vez que se deparar com um erro será mais fácil resolvê-lo conforme ganha experiência, por isso é muito importante que sempre pratique.


Erro 1: Tentar acessar índice inexistente

É um erro recorrente, principalmente quando trabalhamos com loops, nesses casos devemos ter muito cuidado e definir bem o intervalo que queremos.

A mensagem de erro exibida será IndexError: tuple index out of range

In [ ]:
minha_tupla = (1, 2, 3, 4, 5)
minha_tupla[5]

Erro 2: "Dividir" a tupla em um número muito grande ou muito pequeno de variáveis

Pode ocorrer quando recebemos uma tupla como retorno de uma função. Quando não quiser uma das variáveis basta inserir um _ em seu lugar.

Exemplo:

In [ ]:
coordenadas = (10, 40)
x, _ = coordenadas

O erro exibido será ValueError: not enough values to unpack caso exista tentativa de receber mais valores do que o retornado por uma função:

In [ ]:
def retorna_coordenadas():
    return 10, 40

x, y, z = retorna_coordenadas()

O erro exibido será ValueError: too many values to unpack caso exista tentativa de receber menos valores do que o retornado por uma função:

In [ ]:
def retorna_coordenadas():
    return 10, 40, 30

x, y = retorna_coordenadas()

Erro 3: Tentar modificar uma tupla

Lembre-se que tuplas são imutáveis, se quiser modificá-las você pode convertê-las para uma lista.

Caso tente modificar uma tupla tentando atribuir algum valor aos seus índices será exibido o erro TypeError: 'tuple' object does not support item assignment

In [ ]:
# Incorreto
coordenadas = (10, 20)
coordenadas[1] = 40
In [ ]:
# Correto
coordenadas = [10, 20]
coordenadas[1] = 40
In [ ]:
# Convertendo tupla para lista:
minha_tupla = (1, 2, 3, 4, 5)
minha_lista = list(minha_tupla)