Você está na página 1de 30

Raciocínio Computacional

UNIDADE 07

Menos erros e mais dados – arquivos e exceções

Nesta unidade trabalharemos com dois conceitos importantes: persistência dos


dados em arquivos e o tratamento de exceções. Persistência, neste contexto,
refere-se à capacidade de salvar os dados em algum lugar (no nosso caso, um
arquivo) e recuperarmos aqueles dados quando quisermos. Já as exceções são
aquelas mensagens de erro do Python que aparecem quando tentamos acessar
um dado inexistente ou quando tentamos fazer alguma operação inválida. Agora,
por que você deveria saber sobre essas coisas? No mercado de trabalho é comum
trabalharmos com persistência de dados para enviarmos e recebermos
informações de outros sistemas, ou para termos uma compatibilidade na hora de
transferir dados para outros sistemas escritos por diferentes pessoas e em
diferentes linguagens de programação ou, ainda, como uma forma de termos um
backup dos dados. Já no lado das exceções, saber como tratá-las ajuda a mostrar
mensagens mais amigáveis para o usuário (é melhor mostrar uma mensagem
mais bonita e apresentável ao usuário do que aqueles erros-padrão do Python,
né?), para garantir que o algoritmo continue funcionando mesmo que algum erro
tenha sido detectado e, ainda, melhorar a segurança do seu algoritmo ao tratar
adequadamente alguma entrada maliciosa de dados.

Manipulando arquivos

Você se lembra no início da disciplina quando apresentamos as funções input() e


print() para você? Pois bem: estas duas funções tratavam de ler coisas que o usuário
digitou no terminal e mostrar (escrever) mensagens na tela, certo?

Bom, existem funções para fazer as mesmas operações de leitura e escrita em arquivos.
Para usá-las, precisaremos primeiramente informar um arquivo e abrí-lo. Imagine que
você está trabalhando como um entregador de pizzas: para que você possa entregar a
pizza você precisa, antes de mais nada, saber onde você deverá entregar a pizza, não é?

DICA
Testaremos primeiro alguns exemplos de código e, em seguida,
explicaremos o que este código significa. Por isso, é interessante
que você teste os códigos enquanto vamos os apresentando para
você.

Portanto, vamos começar com um exemplo simples. Teste o código abaixo:

with open("dados.txt", "w") as arquivo:


arquivo.write("Counter-Strike é melhor do que Valorant.")
arquivo.write("O correto é 'bolacha'.")

Vamos analisar passo a passo o que esse código faz:


1. with open("dados.txt", "w") as arquivo:: Aqui, estamos usando a
palavra-chave reservada with, uma construção em Python que garante que o arquivo
seja fechado corretamente após o seu uso. Estamos abrindo o arquivo chamado
"dados.txt" em modo de escrita ("w"), que permite escrever no arquivo. Se o arquivo
não existir, ele será criado. A variável arquivo é associada ao arquivo aberto. Veja que
usamos esse with de um jeito bem parecido com o if/elif/else, for ou while.

1.arquivo.write("Counter-Strike é melhor do que


Valorant."): Nesta linha, estamos chamando o método write() na variável arquivo.
Isso permite escrever o conteúdo especificado entre parênteses no arquivo aberto. No
caso, estamos escrevendo a string "Counter-Strike é melhor do que Valorant." no
arquivo.

2.arquivo.write("O correto é 'bolacha'."): Na próxima linha,


chamamos novamente o método write() para adicionar mais uma frase ao arquivo.
Aqui, estamos escrevendo a frase "O correto é 'bolacha'.".

3.O bloco with é encerrado e, automaticamente, o arquivo é fechado. Isso é


importante para garantir que os recursos do sistema operacional associados ao arquivo
sejam liberados corretamente, e que não apareça algum tipo de mensagem dizendo
que você não poderia modificar o seu arquivo porque ele estaria em uso.

Agora, e se quisermos ler o conteúdo de um arquivo? Teste isto:

with open("dados.txt", "r") as arquivo:


linhas = arquivo.readlines()
print(linhas)

Vamos analisar este código:

1. with open("dados.txt", "r") as arquivo::Aqui, voltamos a usar a


palavra-chave with para abrir o arquivo. A diferença em relação ao exemplo anterior é a
de que estamos usando o modo de leitura ("r"). Isso permite que possamos ler (ao invés
de escrever) o conteúdo do arquivo. A variável arquivo é associada ao arquivo aberto.

1. linhas = arquivo.readlines(): Nesta linha, estamos chamando o


método readlines() na variável arquivo. Esse método lê todas as linhas do arquivo e
retorna uma lista de strings, onde cada elemento da lista representa uma linha do
arquivo. Essa lista é atribuída à variável linhas.
2. print(linhas): Por fim, estamos utilizando a função print() para exibir
o conteúdo da lista linhas, ou seja, todas as linhas do arquivo.

1. O resultado disso será ["Counter-Strike é melhor do que Valorant.O


correto é 'bolacha'."]

3. O bloco with é encerrado e, automaticamente, o arquivo é fechado. Isso


garante que os recursos do sistema operacional (como memória e processador)
associados ao arquivo sejam liberados corretamente.

Bom, agora que passamos por estas demonstrações simples é importante entendermos
como usar as funções de leitura e escrita de arquivos. Vamos lá:

1. Função open(): serve para abrir um arquivo. Use-a toda vez que for ler ou escrever
dados em um arquivo.

Primeiro parâmetro: o nome do arquivo a ser utilizado.


Segundo parâmetro: o modo a ser usado para manipular o arquivo. Os modos
são:
'r' (read, ou leitura): usamos este modo para lermos os dados de um
arquivo.
'w' (write, ou escrita): usamos este modo para escrevermos dados em
um arquivo.
Se o arquivo já existir, todo o conteúdo que já existia será apagado e
substituído pelo novo conteúdo.
Se o arquivo não existir, ele será criado automaticamente com o
novo conteúdo que queremos armazenar em seu interior.
'a' (append, ou escrita no final do arquivo): usamos este modo para
escrevermos dados no final de um arquivo sem apagar o conteúdo já
existente.

2. Agora que o arquivo está aberto, você pode ler ou escrever coisas (mais
precisamente, strings).
Escrever coisas:
1. Escrever uma string no arquivo: função write().
2. Esta função não aceita números ou booleanos: você precisará
converter para string.
Ler coisas:
1. Ler uma linha de cada vez: função readline().
2. Ler todo o conteúdo do arquivo em uma só string: função read().
3. Ler todo o conteúdo do arquivo separando linha por linha como
strings em uma única lista: função readlines().
Vamos pensar em mais alguns exemplos para testarmos?

Exemplo de aplicação 1: Crie uma aplicação a qual pede o nome do usuário. Em


seguida, salve em um arquivo chamado “nome.txt” o nome desta pessoa.

nome = input("Digite o seu nome: ")

with open("nome.txt", "w") as f:


f.write(nome)

Veja novamente o bloco with open("nome.txt", "w") as f:. Ele é responsável


por abrir o arquivo "nome.txt" no modo de escrita ("w") em uma variável chamada f.
Utilizando esta variável f, chamamos o método write() para escrever o conteúdo da
variável nome no arquivo.

Exemplo de aplicação 2: Usando o exemplo de aplicação 1, leia o nome salvo no


arquivo “nome.txt”, mostrando cada caractere em uma linha separada.

with open("nome.txt", "r") as f:


conteudo = f.read()

for letra in conteudo:


print(letra)

Veja que, como estamos lendo o arquivo, agora o bloco é with open("nome.txt",
"r") as f:. Aquele "r" indica que estamos abrindo o arquivo "nome.txt" no modo de
leitura. O conteúdo do arquivo é lido e armazenado na variável conteudo.

Depois, usamos um for para mostrar cada letra dentro de uma única linha.

Exemplo de aplicação 3: Salve dois números decimais em novas linhas do mesmo


arquivo “nome.txt”.

primeiro_numero = 1.01
segundo_numero = -2.95

with open("nome.txt", "a") as f:


f.write("\n" + str(primeiro_numero))
f.write("\n" + str(segundo_numero))

Viu que o bloco começa com with open("nome.txt", "a") as f:? Aquele "a" indica que
somente estamos acrescentando dados no arquivo sem apagar o que já tínhamos
armazenado antes. É esta a diferença principal entre o modo "a" e "w".

Depois, perceba que temos dois write(): eles servem para que armazenemos os dois
números no arquivo. Perceba também duas coisas:

1. Tivemos que converter os números para texto primeiro com o str() (mais
especificamente, com o str(primeiro_numero) e str(segundo_numero)). Isto era
importante porque não somente conseguimos salvar strings no arquivo. Por isso,
precisamos converter os números para strings antes de salvá-los no arquivo.

2. Perceba também que colocamos no início de cada escrita de arquivo um “\n”. Este
caracter significa “line feed”, ou “quebra de linha”. Isto garante com que salvemos cada
número em uma linha separada.

Exemplo de aplicação 4: Leia novamente o conteúdo do arquivo “nome.txt”. Agora, leia


uma linha de cada vez, e mostre o conteúdo de cada linha na tela.

with open("nome.txt", "r") as f:


for linha in f.readlines():
print(linha)

Perceba que alguns comportamentos se repetem: o bloco de leitura do arquivo com o


with, e a abertura do arquivo em modo de leitura (“r”). Agora, veja que o conteúdo do
f.readlines() é uma lista de strings. Cada string é uma linha do arquivo. Como é uma
lista, estamos usando o for para mostrar cada linha individualmente na tela para o
usuário.

Arquivos JSON

Agora, e se quiséssemos salvar os arquivos de uma forma padronizada? Isto é: e se


quiséssemos transferir dados entre diferentes sistemas seguindo algum tipo de padrão
internacional em que toda empresa de tecnologia saberia (ou deveria saber) como
funciona?

É aí que entram os arquivos JSON. JSON (JavaScript Object Notation) é um formato leve
e de fácil leitura utilizado para a troca de dados entre sistemas. Ele é amplamente
utilizado na comunicação entre aplicativos web e é suportado por várias linguagens de
programação, incluindo o Python.

O JSON é baseado em uma estrutura de dados composta por pares de chave e valor.
Esses pares são organizados em uma sintaxe simples e legível, permitindo representar
informações de forma estruturada. A estrutura básica do JSON consiste em objetos e
arrays (vetores, ou listas).

1. Objetos: são delimitados por chaves {} e consistem em uma coleção não ordenada
de pares chave-valor. Cada chave é uma string única que identifica o valor
associado a ela. Os pares chave-valor são separados por vírgulas.
2. Arrays: são delimitados por colchetes [] e podem conter uma lista ordenada de
valores. Os valores em um array podem ser de qualquer tipo válido do JSON,
incluindo strings, números e outros arrays. Os elementos do array são separados
por vírgulas.

Veja só um exemplo:

{
"nome": "João",
"idade": 25,
"cidade": "Curitiba",
"frutas_favoritas": [
"maçã",
"banana",
"laranja"
]
}

Aqui, todas estas linhas fazem parte de um único objeto JSON. Este objeto possui
quatro chaves (nome, idade, cidade e frutas_favoritas). A chave “nome” armazena uma
string, a chave “idade” armazena um número inteiro, e a chave “cidade” armazena
outra string. Já chave “frutas_favoritas” armazena um array de três valores (percebeu
os colchetes?).

Além disso, o JSON suporta diferentes tipos de dados, como strings, números,
booleanos, valores nulos, listas e matrizes. Agora, para que usamos JSON no mercado
de trabalho? Um dos principais usos é na interoperabilidade entre sistemas (isto é: para
trocar dados entre sistemas escritos em linguagens de programação e empresas
diferentes).

Por ser um formato padrão amplamente adotado no mundo inteiro, ele permite a troca
de dados entre diferentes sistemas e plataformas. É comum utilizar JSON para enviar e
receber dados de APIs (Application Programming Interfaces), permitindo a integração de
sistemas de maneira eficiente.

IMPORTANTE
Percebeu que isso é muito parecido com os dicionários, não é?
Isto não é coincidência.

Vamos para alguns exemplos usando arquivos JSON? Ao contrário da leitura e escrita
de arquivos usando strings em que usávamos write() ou read()/readline()/readlines(),
aqui utilizaremos outras duas funções: dump() e load(). Ambas existem em um módulo
específico do Python para a manipulação de arquivos JSON e que também tem o nome
de json, e elas já realizam todas as conversões de dados que precisamos de forma
automática. Vejamos:

Exemplo de aplicação 5: Salve o exemplo de JSON acima em um arquivo chamado


“pessoa.json”.

import json

dados = {
"nome": "João",
"idade": 25,
"cidade": "Curitiba",
"frutas_favoritas": [
"maçã",
"banana",
"laranja"
]
}

with open("pessoa.json", "w", encoding="utf-8") as arquivo:


json.dump(dados, arquivo, ensure_ascii=False)

Vamos por partes:


1. import json:Nesta linha, estamos importando o módulo json da biblioteca
padrão do Python. Esse módulo fornece funções para trabalhar com JSON. Sem isso,
não conseguiremos ler e salvar dados em JSON.

2. dados = { ... }:Neste trecho temos um dicionário contendo várias


informações sobre uma pessoa.

3. with open("pessoa.json", "w", encoding="utf-8") as arquivo::


Aqui, estamos abrindo um arquivo chamado “pessoa.json” em modo de escrita (“w”).

Percebeu aquele encoding=”utf-8”? Definimos este parâmetro para garantir


que caracteres especiais (como o “ã” e “ç”) sejam tratados corretamente.

4. json.dump(dados, arquivo, ensure_ascii=False): Nesta linha, estamos


usando a função json.dump() para escrever o conteúdo do dicionário dados no arquivo
JSON aberto.

A função dump() recebe três argumentos: o dicionário dados que será


convertido em JSON, a variável arquivo onde os dados serão gravados e o
parâmetro ensure_ascii=False para permitir a codificação correta de
caracteres não-ASCII (isto é, caracteres que não façam parte do alfabeto da
língua inglesa).

Contexto: o código de caracteres ASCII era usado nos primeiros dias da


Computação para mapear os caracteres em computadores. Ele possui 128
caracteres, incluindo letras maiúsculas e minúsculas, números e símbolos de
pontuação.

Ainda que isto funcionasse bem para quem trabalhasse somente com dados
em inglês, ele não é compatível com todos os alfabetos e símbolos especiais
do mundo. Por isso, hoje é normal usarmos outro código mais amplo: o UTF-8
(Unicode). Ele é adequado para aplicações multilíngues e internacionais. Os
emojis fazem também parte do UTF-8.

DICA
um módulo é como uma "biblioteca" de código que pode ser
importada para adicionar funcionalidades extras ao seu
programa. Para utilizar um módulo em seu programa, você
precisa importá-lo. A declaração import nome_do_modulo
permite acessar todas as definições contidas no módulo. Você
pode usar as funções, classes e variáveis do módulo em seu
programa conforme necessário. Por isso, usamos o import json
no começo do nosso arquivo: sem ele, não conseguiríamos ler e
escrever informações em JSON.

Agora, e como leríamos os dados de um arquivo JSON para uma variável? Basta
usarmos a função load(). Vejamos:

Exemplo de aplicação 6: Leia o conteúdo do arquivo “pessoa.json” e armazene-o em


uma variável chamada dados_lidos.

import json

with open("pessoa.json", "r", encoding="utf-8") as arquivo:


dados_lidos = json.load(arquivo)

print(dados_lidos)

Vamos por partes:

1. import json:Como temos que ler os dados do arquivo json (mais


especificamente, precisaremos usar a função load()), precisaremos primeiro importar o
módulo json.

2. with open("pessoa.json", "r", encoding="utf-8") as arquivo:


Estaremos lendo o conteúdo do arquivo pessoa.json em modo de leitura (“r”). Como
poderemos ter caracteres especiais (isto é, com acentos), usamos também o parâmetro
encoding="utf-8" para evitarmos qualquer tipo de erro.

3. dados_lidos = json.load(arquivo):Nesta linha, estamos usando a


função json.load() para ler o conteúdo do arquivo JSON aberto e armazená-lo na
variável dados_lidos. A função load() carrega o conteúdo do arquivo JSON e converte-o
em uma estrutura de dados Python, como um dicionário ou uma lista, dependendo do
conteúdo do arquivo JSON.
4.Finalmente, mostramos o conteúdo do arquivo lido (que agora é um dicionário)
com o print(). Perceba que alguns comportamentos se repetem: o bloco de leitura do
arquivo com o with, e a abertura do arquivo em modo de leitura (“r”).

IMPORTANTE
Também é possível usar o json.load()/json.dump() para lermos e
escrevermos listas de dicionários em Python. Será que você não
tem nenhuma atividade que solicitava algo assim?

Videoaula

Que tal nos aprofundarmos na interação dos arquivos JSON? Para isso, assista abaixo a
videoaula sobre manipulação de arquivos e arquivos JSON.

Arquivos e JSON

Arquivos binários

Um arquivo binário é um arquivo cujo conteúdo está em um formato binário: uma série
de bytes sequenciais, normalmente cada um possuindo oito bits de comprimento. O
conteúdo deve ser interpretado por um programa ou um processador de hardware que
entenda antecipadamente a forma exata como esse conteúdo é formatado e como ler
os dados.

Normalmente, o binário é utilizado quando não existe necessidade de interpretação


pelo ser humano ou quando se necessita de desempenho. Os arquivos binários incluem
um amplo conjunto de tipos de arquivo como, por exemplo, vídeos, fotos, músicas,
bancos de dados, arquivos executáveis, jogos, entre outros. As variáveis em Python
também podem ser interpretadas como dados binários.

Em Python podemos usar o módulo pickle para ler e salvar variáveis sem passar por
nenhum tipo de conversão. Vamos supor que você precise salvar uma variável que
não é um dicionário: logo, você não poderá usar JSON. E, para ajudar, esta variável não
é uma string: logo, usar o que aprendemos com as funções
write()/read()/readline()/readlines() não seria a melhor alternativa. Vejamos o exemplo
abaixo:

Exemplo de aplicação 7: Salve uma lista de números inteiros em um arquivo chamado


“dados.pickle”.

import pickle

dados = [1, 2, 3, 4, 5]

with open("dados.pickle", "wb") as arquivo:


pickle.dump(dados, arquivo)

O processo é semelhante aos outros exemplos que fizemos até agora. As diferenças são:

1. Abrimos o arquivo em modo de escrita binário ("wb”), e não no modo de escrita


de texto (“w”);
2. Usamos o módulo pickle para manipular arquivos binários responsáveis por
guardar variáveis do Python;
3. Usamos o pickle.dump() para armazenar uma variável (neste exemplo, a variável
dados) dentro do arquivo.

DICA
O pickle permite que você armazene e recupere uma ampla
variedade de objetos Python, incluindo listas, tuplas, conjuntos,
classes personalizadas e muito mais. Basta passar o objeto
desejado como argumento para a função pickle.dump(). Use o
pickle quando precisar armazenar e recuperar objetos Python
completos preservando a sua estrutura e tipos de dados.

Agora, e para lermos estes dados?

Exemplo de aplicação 8: Leia o conteúdo do arquivo “dados.pickle” e armazene-o em


uma variável chamada “variavel_lida”.

import pickle

with open("dados.pickle", "rb") as arquivo:


variavel_lida = pickle.load(arquivo)

print(variavel_lida)

Novamente: a forma de operarmos o arquivo é muito parecida com o que vimos nos
exemplos anteriores. Algumas mudanças são:

1. Lemos o conteúdo do arquivo pickle no modo binário (“rb”) ao invés do modo de


leitura de texto (“r”);
2. Lemos o conteúdo do arquivo usando a função pickle.load().
3. Armazenamos o conteúdo lido do arquivo em uma variável – no caso,
variavel_lida.

Exceções

O que aconteceria se eu pedisse para você digitar um número e, em seguida, mostrasse


na tela o resultado da sua divisão por zero? Bom – teste o código abaixo:

numero = int(input("Digite um número: "))


print(numero/0.0)

Deve ter aparecido algo assim na sua tela, não?


/Users/user/untitled1/bin/python
/Users/user/projects/untitled1/Ex07.py

----------------------------------------------------------
-----------------

ValueError Traceback (most


recent call last)

in ()

----> 1 numero = int("Digite um número: ")

2 print(numero/0.0)

ValueError: invalid literal for int() with base 10:


'Digite um número: '

Coloque-se no lugar de um usuário do seu algoritmo: quais problemas temos com um


erro assim?

1. Não é nada intuitivo;


2. É tudo em inglês, e cheio de termos técnicos;
3. É feio;
4. Revela partes do seu código-fonte as quais você não necessariamente quer
compartilhar com as pessoas: isso pode ser perigoso em um aplicativo de internet
banking, por exemplo.

Erros como os que vimos acima que interrompem a execução de um algoritmo são
chamados de exceções. Veja só: em programação, as exceções são eventos que ocorrem
durante a execução de um programa e podem interromper o fluxo normal das coisas.
Elas representam situações em que algo deu errado, ou em que algo inesperado
aconteceu.

As exceções são como alertas que indicam que algo está errado. Quando uma exceção
ocorre, o programa para e olha ao redor em busca de ajuda para lidar com o problema.
É como se ele dissesse: "Ei, algo deu errado aqui, e não sei como resolver isso. O que eu
devo fazer?".

Tratamento de exceções

Quando essas exceções acontecem é comum que não queremos que o nosso programa
simplesmente trave e pare de funcionar: queremos lidar com essa situação de forma
adequada. A definição de “adequada” depende de cada caso. Pode ser uma mensagem
bonita para o(a) usuário falando que a operação que ele(a) está fazendo é inválida, ou
forçar um valor padrão ou, ainda, direcionar o algoritmo para executar algum outro
pedaço de código. Isto é um tratamento de exceção: uma forma de dizer ao programa
como lidar com a exceção quando ela ocorre.

DICA
Tratamento de exceções é como ter um plano de contingência
para quando algo dá errado.

Em Python, usamos as palavras-chave try e except para definir um bloco de tratamento


de exceção. Dentro do bloco try, colocamos o código que pode gerar uma exceção. E
dentro do bloco except, colocamos o código que será executado se a exceção ocorrer.

Dessa forma, podemos tratar erros específicos de forma adequada, exibindo


mensagens de erro amigáveis para o usuário, realizando ações alternativas ou até
mesmo evitando que o programa pare completamente.

Vamos a alguns exemplos?

Exemplo de aplicação 9: Adicione um tratamento de exceções para um algoritmo que


pede ao usuário para que ele(a) digite um número e, em seguida, dividisse aquele
número por zero.

numero = int(input("Digite um número: "))

try:
print(numero/0.0)
except:
print("Não foi possível dividir o número por zero.")
Perceba que modificamos o exemplo inicial da divisão por zero. Colocamos dentro do
try a(s) linha(s) de código que podem dar erro e, dentro do bloco except, o código que
deverá ser executado se o que estiver dentro do try não funcionar.

Se você testar o código acima, verá que aquela exceção que vimos anteriormente
desapareceu: em seu lugar, apareceu uma mensagem mais amigável de erro.

Exemplo de aplicação 10: Mostre um menu simples com opções numéricas ao usuário.
Converta a opção digitada para um número inteiro. Mostre uma mensagem simples de
erro se o valor digitado for inválido (como um texto).

while True:
print("1. Doces")
print("2. Salgados")
print("3. Bebidas")
print("4. Sair")

try:
opcao = int(input("Digite uma opção:"))
except:
print("Você digitou uma opção inválida. Tente
novamente.")
continue

if opcao >= 1 and opcao <= 3:


print(f"Você digitou a opção válida \"{opcao}\".")
elif opcao == 4:
break
else:
print("Você digitou uma opção inválida. Tente
novamente.")

Vamos nos focar no bloco try/except: o código dentro do bloco try está tentando
converter a entrada do usuário em um número inteiro usando a função int(input()). Se
o usuário digitar algo que não possa ser convertido em um número inteiro (como o
texto “chinelo”), uma exceção será gerada.

Se ocorrer uma exceção, o bloco except será executado. Nesse caso, uma mensagem de
erro será exibida informando que uma opção inválida foi digitada, e o loop retornará ao
início graças à palavra-chave continue. Se o continue não existisse, o bloco if/elif/else
seria executado. Como já sabemos que a opção digitada é inválida, estamos forçando o
reinício do loop.
EXERCÍCIO
Exercício de fixação 1: Crie um programa que peça ao usuário
uma 5 números inteiros. Salve estes números dentro de um
arquivo chamado “números.txt”. Cada número deve ocupar uma
linha.

Resolução do exercício

Resolução exercício 1

lista_numeros = []
for i in range(5):
numero = int(input("Digite um número
inteiro: "))
lista_numeros.append(numero)

with open("números.txt", "w") as arquivo:


for numero in lista_numeros:
arquivo.write(str(numero) + "\n")

Exercício de fixação 2: Crie um programa que leia o arquivo


“números.txt” do exercício anterior, e calcule a soma desses
números.

Resolução do exercício

Resolução exercício 2

soma = 0
with open("números.txt", "r") as arquivo:
for linha in arquivo.readlines():
soma += int(linha)
print(soma)

Exercício de fixação 3: Crie um programa que escreva um arquivo


chamado "alunos.txt" contendo informações de alunos (um aluno
por linha, separado por vírgulas - nome, idade, nota) conforme a
lista abaixo. Dica: se quiser, pesquise sobre a função “map” em
Python. Ela serve para substituir o “for” em alguns casos.

alunos = [
("João", 18, 9.5),
("Maria", 19, 8.7),
("Pedro", 20, 7.2),
("Ana", 18, 9.0),
("Carlos", 19, 8.5)
]

Resolução do exercício

Resolução exercício 3

alunos = [
("João", 18, 9.5),
("Maria", 19, 8.7),
("Pedro", 20, 7.2),
("Ana", 18, 9.0),
("Carlos", 19, 8.5)
]

with open("alunos.txt", "w") as arquivo:


for aluno in alunos:
linha = ",".join(map(str, aluno))
+ "\n"
arquivo.write(linha)
Exercício de fixação 4: Crie um programa que leia o arquivo
"alunos.txt" do exercício anterior. Em seguida, calcule a média
das notas dos alunos e exiba na saída padrão. Dica: se quiser,
pesquise sobre o método “split” em Python. Ele serve para dividir a
string em strings menores.

Resolução do exercício

Resolução exercício 4

with open("alunos.txt", "r") as arquivo:


notas = []
for linha in arquivo:
dados = linha.split(",")
notas.append(float(dados[2]))

media = sum(notas) / len(notas)


print("A média das notas dos alunos
é:", media)

Exercício de fixação 5: Crie um programa que salva uma lista de


dicionários em um arquivo chamado “exemplo.json” usando
como base a lista abaixo:

dados = [
{"nome": "João", "idade": 25,
"cidade": "Curitiba"},
{"nome": "Maria", "idade": 30,
"cidade": "São Paulo"},
{"nome": "Carlos", "idade": 28,
"cidade": "Rio de Janeiro"}
]

Resolução do exercício
Resolução exercício 5

import json

dados = [
{"nome": "João", "idade": 25,
"cidade": "Curitiba"},
{"nome": "Maria", "idade": 30,
"cidade": "São Paulo"},
{"nome": "Carlos", "idade": 28,
"cidade": "Rio de Janeiro"}
]

with open("exemplo.json", "w",


encoding='utf-8') as arquivo:
json.dump(dados, arquivo,
ensure_ascii=False)

Exercício de fixação 6: Crie um programa que lê o conteúdo do


arquivo “exemplo.json” do exercício anterior. Salve o conteúdo
em um dicionário. Mostre o conteúdo do dicionário na tela.

Resolução do exercício

Resolução exercício 6

import json

with open("exemplo.json", "r",


encoding='utf-8') as arquivo:
conteudo = json.load(arquivo)

print(conteudo)
Cadastro de Clientes, Parte II

Lembra do exemplo do sistema para cadastro de clientes que vimos anteriormente? O


nosso código com o uso de funções havia ficado desse jeito:

def menu():
print("\nMenu:")
print("1. Inserir clientes")
print("2. Editar clientes")
print("3. Listar clientes")
print("4. Pesquisar clientes")
print("5. Sair")

def inserir_cliente(clientes):
nome = input("Insira o nome do cliente: ")
clientes.append(nome)
print(f"Cliente {nome} adicionado.")

return clientes

def editar_cliente(clientes):
nome_antigo = input("Insira o nome do cliente a ser
editado: ")
if nome_antigo in clientes:
nome_novo = input("Insira o novo nome do cliente:
")
indice = clientes.index(nome_antigo)
clientes[indice] = nome_novo
print(f"Cliente {nome_antigo} alterado para
{nome_novo}.")
else:
print("Cliente não encontrado.")

return clientes

def listar_clientes(clientes):
print("Lista de clientes:")
for cliente in clientes:
print(cliente)

return None

def pesquisar_clientes(clientes, nome):


if nome in clientes:
return True
else:
return False
clientes = []

while True:
menu()
opcao = int(input("Escolha uma opção: "))

if opcao == 1:
clientes = inserir_cliente(clientes)
elif opcao == 2:
clientes = editar_cliente(clientes)
elif opcao == 3:
listar_clientes(clientes)
elif opcao == 4:
nome = input("Insira o nome do cliente a ser
pesquisado: ")
if pesquisar_clientes(clientes, nome):
print(f"Cliente {nome} está na lista.")
else:
print("Cliente não encontrado.")
elif opcao == 5:
print("Saindo do programa...")
break
else:
print("Opção inválida. Tente novamente.")

Agora, e se quiséssemos melhorar o nosso código? Pensemos na inclusão das seguintes


funcionalidades:

1. Armazenar e atualizar em um arquivo JSON o cadastro dos clientes.


2. Incluir tratamento de exceções.

Adaptaremos o nosso código por partes. Vamos lá?

Para trabalharmos com persistência precisaremos sempre ler e escrever qualquer


atualização em um arquivo JSON. Isto é: toda vez que inserirmos, editarmos ou
excluirmos alguma coisa será necessário atualizar o arquivo JSON. O nosso código
somente possui as funcionalidades de inserir e editar clientes. Logo, nos focaremos
nestas duas funcionalidades.

A primeira coisa que sugiro que façamos é a de implementar duas novas funções: uma
para ler e outra para escrever arquivos JSON. Isto é importante sob um ponto de vista
de testes: criar funções separadas permite que testemos somente a lógica de
manipulação de arquivos JSON sem precisar que nos preocupemos em testar (ou
quebrar) todo o código já existente. Com o que aprendemos até agora, poderíamos ter
duas funções assim:
def escrever_lista_em_json(lista, nome_arquivo):
with open(nome_arquivo, "w") as arquivo:
json.dump(lista, arquivo)

def ler_lista_do_json(nome_arquivo):
try:
with open(nome_arquivo, "r") as arquivo:
lista = json.load(arquivo)

return lista
except:
return []

A primeira função recebe dois parâmetros: a lista que queremos salvar e o nome do
arquivo em que ficará a lista. Já a segunda função recebe como parâmetro de entrada o
nome do arquivo e retorna a lista que está dentro daquele arquivo. Na segunda função
adicionei um try/except simples só para os nossos primeiros testes: se o arquivo ainda
não existir retornaremos uma lista vazia em vez de um erro.

Até poderíamos testar estas duas funções assim:

escrever_lista_em_json([1, 2, 3], "teste.json")


lista_lida = ler_lista_do_json("teste.json")
print(lista_lida)

Na primeira linha, estamos escrevendo uma lista qualquer de três números em um


arquivo chamado “teste.json”. Depois, estamos testando a leitura daquele arquivo ao
armazenar o conteúdo em uma variável chamada “lista_lida”. O nosso print() deve estar
mostrando a mesma lista de três números na tela.

Testou? Funcionou? Ótimo! Podemos avançar. O próximo passo será modificar as


funções que manipulam os clientes para que elas comecem a ler e escrever do arquivo
JSON diretamente. Logo, a próxima tarefa será alterar as funções que usavam a lista
para que elas possam ler e escrever o arquivo JSON diretamente.

As funções que usavam a lista “clientes” são:

1. inserir_cliente();
2. editar_cliente();
3. listar_clientes();
4. pesquisar_clientes().
Comecemos pela função inserir_cliente(). Hoje, ela está assim:

def inserir_cliente(clientes):
nome = input("Insira o nome do cliente: ")
clientes.append(nome)
print(f"Cliente {nome} adicionado.")

return clientes

Como queremos tirar a dependência direta daquela lista “clientes” e passar a consumir
do arquivo JSON diretamente, faremos as seguintes alterações:

1. Deixaremos de ler como parâmetro de entrada a lista “clientes” e passaremos a ler


como parâmetro de entrada o nome do arquivo JSON em que deveremos salvar a
lista de clientes.
2. Antes de fazermos o .append() precisaremos pegar o conteúdo mais atualizado do
arquivo JSON. Por isso, antes de fazermos o .append() precisaremos ler o arquivo
JSON.
3. Depois do .append() salvaremos a lista atualizada no arquivo JSON.

Assim, a função modificada ficaria assim (veja as alterações em negrito e itálico):

def inserir_cliente(nome_arquivo):
clientes = ler_lista_do_json(nome_arquivo)
nome = input("Insira o nome do cliente: ")
clientes.append(nome)
print(f"Cliente {nome} adicionado.")
escrever_lista_em_json(clientes, nome_arquivo)
return None

Sugiro que você teste esta função antes de mais nada. Se fizermos diretamente no
código um inserir_cliente("teste2.json") é provável que a sua função funcione
corretamente, e que o seu cliente seja salvo dentro do arquivo teste2.json.

DICA
Sempre teste uma mudança de cada vez. Assim, você conseguirá
reverter as alterações e entender facilmente qualquer erro no seu
código.
A mesma lógica pode ser aplicada às funções de editar, listar e pesquisar clientes. Hoje,
elas estão assim:

def editar_cliente(clientes):
nome_antigo = input("Insira o nome do cliente a ser
editado: ")
if nome_antigo in clientes:
nome_novo = input("Insira o novo nome do cliente:
")
indice = clientes.index(nome_antigo)
clientes[indice] = nome_novo
print(f"Cliente {nome_antigo} alterado para
{nome_novo}.")
else:
print("Cliente não encontrado.")

return clientes

def listar_clientes(clientes):
print("Lista de clientes:")
for cliente in clientes:
print(cliente)

return None

def pesquisar_clientes(clientes, nome):


if nome in clientes:
return True
else:
return False

Com as nossas mudanças para ler e escrever no arquivo JSON seguindo a mesma lógica
anterior, ficaria assim (alterações em negrito e itálico):

def editar_cliente(nome_arquivo):
clientes = ler_lista_do_json(nome_arquivo)
nome_antigo = input("Insira o nome do cliente a ser
editado: ")
if nome_antigo in clientes:
nome_novo = input("Insira o novo nome do cliente:
")
indice = clientes.index(nome_antigo)
clientes[indice] = nome_novo
print(f"Cliente {nome_antigo} alterado para
{nome_novo}.")
else:
print("Cliente não encontrado.")

escrever_lista_em_json(clientes, nome_arquivo)
return None

def listar_clientes(nome_arquivo):
clientes = ler_lista_do_json(nome_arquivo)
print("Lista de clientes:")
for cliente in clientes:
print(cliente)

return None

def pesquisar_clientes(nome_arquivo, nome):


clientes = ler_lista_do_json(nome_arquivo)
if nome in clientes:
return True
else:
return False

Perceba que sempre começamos as funções lendo o conteúdo do arquivo: isto serve
para que sempre possamos pegar a versão mais atualizada do arquivo JSON. Também
veja que somente escrevemos (atualizamos) o arquivo JSON na função editar_cliente():
afinal, não atualizamos nenhum dado dentro das funções de listar e pesquisar clientes.
Portanto, não seria necessário escrever novamente a lista no arquivo JSON uma vez que
não houve alterações.

Agora, vamos alterar o bloco principal do código. Atualmente, ele está assim:

clientes = []

while True:
menu()
opcao = int(input("Escolha uma opção: "))

if opcao == 1:
clientes = inserir_cliente(clientes)
elif opcao == 2:
clientes = editar_cliente(clientes)
elif opcao == 3:
listar_clientes(clientes)
elif opcao == 4:
nome = input("Insira o nome do cliente a ser
pesquisado: ")
if pesquisar_clientes(clientes, nome):
print(f"Cliente {nome} está na lista.")
else:
print("Cliente não encontrado.")
elif opcao == 5:
print("Saindo do programa...")
break
else:
print("Opção inválida. Tente novamente.")

Alteramos o parâmetro de entrada de várias funções, não é? Quer dizer: deixamos de


usar a lista clientes e passamos a esperar pelo nome_arquivo. Logo, aquela lista
clientes = [] no início não é mais necessária. Vamos substituí-la pelo nome do arquivo
no qual salvaremos os dados dos clientes. Algumas funções passaram também a
retornar None. Veja as mudanças em negrito e itálico, abaixo:

arquivo = 'clientes.json'

while True:
menu()
try:
opcao = int(input("Escolha uma opção: "))
except:
print("Apenas números são permitidos. Tente
novamente.")
continue

if opcao == 1:
inserir_cliente(arquivo)
elif opcao == 2:
editar_cliente(arquivo)
elif opcao == 3:
listar_clientes(arquivo)
elif opcao == 4:
nome = input("Insira o nome do cliente a ser
pesquisado: ")
if pesquisar_clientes(arquivo, nome):
print(f"Cliente {nome} está na lista.")
else:
print("Cliente não encontrado.")
elif opcao == 5:
print("Saindo do programa...")
break
else:
print("Opção inválida. Tente novamente.")

Perceba que já aproveitei e coloquei um try/except adicional: se digitarmos uma opção


que não seja um número o algoritmo continuará funcionando normalmente.

O código final (quer dizer, uma das implementações possíveis) ficará assim:

def escrever_lista_em_json(lista, nome_arquivo):


with open(nome_arquivo, "w") as arquivo:
json.dump(lista, arquivo)

def ler_lista_do_json(nome_arquivo):
try:
with open(nome_arquivo, "r") as arquivo:
lista = json.load(arquivo)

return lista
except:
return []

def menu():
print("\nMenu:")
print("1. Inserir clientes")
print("2. Editar clientes")
print("3. Listar clientes")
print("4. Pesquisar clientes")
print("5. Sair")

def inserir_cliente(nome_arquivo):
clientes = ler_lista_do_json(nome_arquivo)
nome = input("Insira o nome do cliente: ")
clientes.append(nome)
print(f"Cliente {nome} adicionado.")
escrever_lista_em_json(clientes, nome_arquivo)
return None

def editar_cliente(nome_arquivo):
clientes = ler_lista_do_json(nome_arquivo)
nome_antigo = input("Insira o nome do cliente a ser
editado: ")
if nome_antigo in clientes:
nome_novo = input("Insira o novo nome do cliente:
")
indice = clientes.index(nome_antigo)
clientes[indice] = nome_novo
print(f"Cliente {nome_antigo} alterado para
{nome_novo}.")
else:
print("Cliente não encontrado.")

escrever_lista_em_json(clientes, nome_arquivo)
return None

def listar_clientes(nome_arquivo):
clientes = ler_lista_do_json(nome_arquivo)
print("Lista de clientes:")
for cliente in clientes:
print(cliente)

return None

def pesquisar_clientes(nome_arquivo, nome):


clientes = ler_lista_do_json(nome_arquivo)
if nome in clientes:
return True
else:
return False

arquivo = 'clientes.json'

while True:
menu()
try:
opcao = int(input("Escolha uma opção: "))
except:
print("Apenas números são permitidos. Tente
novamente.")
continue

if opcao == 1:
inserir_cliente(arquivo)
elif opcao == 2:
editar_cliente(arquivo)
elif opcao == 3:
listar_clientes(arquivo)
elif opcao == 4:
nome = input("Insira o nome do cliente a ser
pesquisado: ")
if pesquisar_clientes(arquivo, nome):
print(f"Cliente {nome} está na lista.")
else:
print("Cliente não encontrado.")
elif opcao == 5:
print("Saindo do programa...")
break
else:
print("Opção inválida. Tente novamente.")

Referências Bibliográficas

BANIN, S. L. Python 3: conceitos e aplicações uma abordagem didática. São Paulo:


Érica, 2018.

PYTHON SOFTWARE FOUNDATION. Documentação Python 3.9.0. Disponível em:


https://docs.python.org/pt-br/3/. Acesso em: 27 out. 2020.
© PUCPR - Todos os direitos reservados.

Você também pode gostar