{ "cells": [ { "cell_type": "markdown", "id": "82a66505-fcd8-4b96-9b7b-30ff2bdc934d", "metadata": {}, "source": [ "# Saindo da telinha sem cor do terminal: trabalhando com arquivos" ] }, { "cell_type": "markdown", "id": "b44c74c1-3db1-438f-964f-05961245ad58", "metadata": {}, "source": [ "## O que você saberá se você ler todo este capítulo?\n", "\n", "1. Que dá para trabalhar com arquivos em Python ao invés de ficar mexendo só no terminal.\n", "2. A diferença entre arquivos de texto, JSON e pickle.\n", "3. Que trabalhar com arquivos é mais fácil do que parece: é só abrir, escrever (ou ler) e fechar novamente.\n", "4. E que, sob um ponto de vista de trabalho, é muito mais comum usarmos JSON do que outros formatos." ] }, { "cell_type": "markdown", "id": "ccc2470e-8561-4525-8ac7-7fa68b10cab9", "metadata": {}, "source": [ "## Livro de receitas\n", "\n", "Achou que eu esqueci da receita de bolo? Claro que não, jamais esqueceria de um bolo. Com um café então, nem se fala! Bom, vamos imaginar que você tem uma receita de bolo e você quer dar o seu toque pessoal. Transformar aquela receita de bolo da internet em uma *receita de família*, sabe? Quem sabe, você se animou bastante e agora quer fazer o seu próprio caderno de receitas usando como base algumas receitas comuns que você já viu por aí. Como você faria isso?\n", "\n", "Para isso, você precisa abrir o seu caderno, procurar uma folha em branco, e escrever uma nova receita do seu jeito. Precisou mudar algo? Sem problemas: você vai até a folha em que precisará mudar algo e escreve em cima. Ah, e sabe qual é a vantagem disso? Você pode compartilhar com todo mundo: as pessoas podem tirar fotos ou cópias do seu caderno e, com isso, algum dia você poderá ser reconhecido como o maior boleiro (é esse o nome?) do mundo! Quem diria, né? Por causa desse livro aqui você se tornou o maior mestre dos bolos do mundo e até conseguiu comprar um iate, como esse aqui na imagem abaixo.\n", "\n", "
\n", " \"Um\n", "
Créditos: Robert Linder no Unsplash\n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "54a454d3-b6f2-4ddc-b030-3b073821f339", "metadata": {}, "source": [ "Ou, se você quiser continuar estudando desenvolvimento de software, a explicação acima ainda se aplica. Você pode ter percebido que as variáveis que trabalhamos até o momento nunca eram salvas no seu computador, não é? Isto é: você clicava em `Run`, o seu código aparecia no terminal, você interagia com ele, e acabou. Tirou o computador da tomada, ou acabou a bateria do notebook? Todas as variáveis foram apagadas.\n", "\n", "Por outro lado, os arquivos existem para ajudar a salvar e transmitir esta informação para outros lugares. *E se* nós quiséssemos usar Python para adicionar, modificar ou excluir informações de um arquivo? É possível? Claro que é! É isto que veremos a partir de agora. Vamos lá?" ] }, { "cell_type": "markdown", "id": "84e1160a-b4b9-483f-be6d-581944d9b372", "metadata": {}, "source": [ "## Abrindo e fechando arquivos\n", "\n", "Lembra que no pseudocódigo tínhamos o `leia` e `escreva`, né? E que, em Python, eles eram traduzidos como `input()` e `print()`. Então, será que o Python teria algo para `abrir` e `fechar` arquivos? Mas é claro! E, como você deve adivinhar, os nomes das funções para isso são `open()` e `close()`, respectivamente. Vamos começar com um trabalho simples: vamos escrever uma receita de bolo *dentro* de um arquivo em Python.\n", "\n", "### Criando coisas\n", "Rode o código abaixo em um arquivo `.py`, tal qual você vem fazendo até o momento no PyCharm:\n", "\n", "```python\n", "with open(\"receita.txt\", \"w\") as f:\n", " f.write(\"Bolo de chocolate\\n\")\n", " f.write(\"Ingredientes:\\n\")\n", " f.write(\"- 2 xícaras de açúcar\\n\")\n", " f.write(\"- 1 e 3/4 xícaras de farinha de trigo\\n\")\n", " f.write(\"- 3/4 xícara de cacau em pó\\n\")\n", " \n", "print(\"Finalizou!\")\n", "```\n", "\n", "Muita coisa nova, né? Agora tem `with`, tem `open`, tem aquele `\"w\"` também. O que quer dizer tudo isso? Calma! É mais simples do que parece. Este código cria um arquivo chamado `\"receita.txt\"` no modo de escrita (`\"w\"`) usando a função `open()` na primeira linha. Ou seja, `open(\"receita.txt\", \"w\")` é, em bom português, algo como *\"abra um arquivo chamado \"receita.txt\" para a gente escrever coisas dentro dele\"*. A partir de agora, nós chamaremos este arquivo aberto pelo nome de `f`.\n", "\n", "Ah, veja que a primeira linha também possui o `with`. Essa palavra-chave existe para garantir que o arquivo seja fechado após o uso dele.\n", "\n", "Já a função `write()` é usada para escrever cada linha da receita no arquivo `f` que acabamos de abrir anteriormente. Perceba que chamamos o `write()` cinco vezes: estamos escrevendo coisas no arquivo cinco vezes, e uma linha de texto a cada vez. Consegue perceber que isso é bem parecido com o jeito que estamos acostumados a usar o `print()`?\n", "\n", "Ao final da execução do bloco `with`, o nosso arquivo é automaticamente fechado, e todas as alterações feitas durante a execução do bloco são salvas. No final, temos até uma mensagem na tela mostrando que o código finalizou. Depois de rodar este código, experimente abrir o arquivo `receita.txt`, que agora existe em seu computador e na mesma pasta em que está o seu arquivo `.py`. Percebe que contém exatamente as mesmas 5 linhas que pedimos para serem inseridas antes?\n", "\n", "### Lendo coisas\n", "Bom, e para lermos o arquivo? Teste o seguinte código:\n", "\n", "```python\n", "with open(\"receita.txt\", \"r\") as f:\n", " conteudo = f.read()\n", " print(conteudo)\n", "```\n", "\n", "Percebe que trocamos o `open(\"receita.txt\", \"w\")` para `open(\"receita.txt\", \"r\")`? O parâmetro `\"r\"` indica que agora estamos no modo de leitura: ao invés de escrever, queremos ler o arquivo. Em seguida, usamos o método `.read()` para ler todo o conteúdo do arquivo e armazená-lo na variável `conteudo`. Por fim, mostramos o conteúdo na tela utilizando a função `print()`.\n", "\n", "Outro jeito de fazermos a mesmíssima coisa, mas sem recorrermos ao `with` é assim:\n", "\n", "```python\n", "f = open(\"receita.txt\", \"r\")\n", "conteudo = f.read()\n", "print(conteudo)\n", "f.close()\n", "```\n", "\n", "Temos aqui três grandes diferenças. A primeira é que deixamos de usar o `with` na primeira linha, e o arquivo aberto encontra-se ainda dentro da variável `f`, mas com o código escrito de uma forma ligeiramente diferente. A segunda diferença fica na segunda e terceira linhas: como não temos mais o `with`, não temos mais aquela indentação. A terceira diferença está na última linha: sem o `with`, precisamos dizer explicitamente quando o arquivo deve ser fechado com a função `close()`.\n", "\n", "Dito isso, vale reforçar que por uma questão de boa prática é recomendável que você utilize o `with` para evitar dores de cabeça como, por exemplo, esquecer de fechar o seu arquivo.\n", "\n", "### Adicionando coisas\n", "Finalmente, e se quiséssemos só adicionar mais alguma coisinha no arquivo sem apagar o que já temos até o momento? Também tem como. Veja só:\n", "\n", "```python\n", "with open(\"receita.txt\", \"a\") as f:\n", " f.write(\"- 1 colher de sopa de fermento em pó\\n\")\n", " f.write(\"- Granulado a gosto\\n\")\n", "```\n", "\n", "Veja que usamos o `f.write()` igual como fizemos no primeiro exemplo. A diferença está no parâmetro da primeira linha: agora estamos usando `open(\"receita.txt\", \"a\")`. Este `\"a\"` indica que queremos adicionar um conteúdo extra no final deste arquivo sem remover nada do que fizemos até o momento. Em resumo, temos o seguinte:\n", "\n", "### ✍ Resumo\n", "- `open()`: serve para abrir um arquivo.\n", " - Modo `r` (*read*): abre o arquivo para leitura. Se o arquivo não existir, ocorrerá um erro.\n", " - Modo `a` (*append*): abre o arquivo para escrita, adicionando conteúdo ao final do arquivo caso ele já exista. Se o arquivo não existir, ele será criado.\n", " - Modo `w` (*write*): abre o arquivo para escrita, **apagando todo o conteúdo anterior caso ele já exista**. Se o arquivo não existir, ele será criado.\n", " - Também existem outros modos:\n", " - Modo `x` (*exclusive*): cria um arquivo para escrita, mas retorna um erro se ele já existe.\n", " - Modo `b` (*binary*): cria um arquivo para escrita de dados binários como imagens, vídeos, músicas e demais conteúdos que não são texto puro. \n", "- `close()`: serve para fechar um arquivo. Não precisa usar o `close()` se estiver abrindo um arquivo com o `with`.\n", "- `with`: o uso dele é bem parecido com um `if` ou `for`. Ele garante que o arquivo será aberto no início do bloco contendo esta palavra-chave e fechado automaticamente no final do bloco, mesmo que ocorra um erro (exceção)." ] }, { "cell_type": "markdown", "id": "7e64f99c-3798-41ee-a5b4-e9f36c722a88", "metadata": {}, "source": [ "## Escrevendo diferentes tipos de arquivo\n", "\n", "Todos os exemplos acima somente trabalharam com arquivos de texto. Um arquivo de texto (geralmente identificados pela extensão `.txt`, como o `receita.txt` que você testou acima) é um arquivo que contém somente caracteres de texto simples. Isto é: só texto puro, e nada de cores, negrito, itálico, ou fontes diferentes. Ele é usado para armazenar informações de texto em formato legível por humanos e é geralmente usado para processamento de texto, editores de código, manuais simples, entre outros. Isto posto, existem jeitos diferentes de armazenarmos os dados. Para isso, vamos usar um código como exemplo:\n", "\n", "```python\n", "valor_pi = 3.14159\n", "lista_frutas = [\"maçã\", \"banana\", \"laranja\", \"manga\"]\n", "dicionario_pessoas = {\"João\": 25, \"Maria\": 30, \"Pedro\": 20, \"Marcos\": 15}\n", "```\n", "\n", "São três variáveis, e cada um possui um tipo diferente, certo? Uma delas é uma variável do tipo `float`, outra é uma lista e, a outra, um dicionário. Agora, como guardaríamos estas informações em arquivos? Vamos testar de quatro jeitos diferentes: com arquivos de texto (que acabei de explicar o que são), CSVs, JSON e, finalmente, Pickle. Também vamos falar para que servem cada um desses tipos, beleza? Ah, para cada um desses jeitos, salvaremos essas três variáveis em arquivos separados e, depois, abriremos elas para ver como ficaram." ] }, { "cell_type": "markdown", "id": "7a916a0b-f245-4129-a076-11c97a14dc9c", "metadata": {}, "source": [ "### Salvando em texto\n", "Vamos começar escrevendo aquela variável `valor_pi` em um arquivo de texto, o que acha? Usando as mesmas funções que vimos até agora, teríamos:\n", "\n", "```python\n", "# salvar valor_pi em um arquivo txt\n", "with open(\"valor_pi.txt\", \"w\") as f:\n", " f.write(str(valor_pi))\n", "\n", "# ler valor_pi de um arquivo txt \n", "with open(\"valor_pi.txt\", \"r\") as f:\n", " valor_pi_lido = f.read()\n", " print(f'{valor_pi_lido}, tipo {type(valor_pi_lido)}')\n", "```\n", "\n", "Percebe a linha `f.write(str(valor_pi))`? Para salvarmos texto precisaremos, obrigatoriamente, converter as variáveis para texto. É por isso que o valor da variável é convertido em uma string usando a função `str()` antes de o gravarmos no arquivo.\n", "\n", "Quanto à leitura, veja que na penúltima linha estamos lendo o conteúdo do arquivo `valor_pi.txt` usando o modo de leitura `\"r\"` do método `open()`. O conteúdo do arquivo é armazenado na variável `valor_pi_lido` como uma string. Para comprovar isso, veja que na última linha eu mostro na tela o valor de `valor_pi_lido` e o tipo de dado da variável usando a função `print()`. No caso, aquele `type(valor_pi_lido)` mostra na tela o tipo daquela variável que, no caso, é uma string.\n", "\n", "O resultado, portanto, seria:\n", "```bash\n", "3.14159, tipo \n", "```\n", "\n", "Quer converter aquele valor lido do arquivo de volta para um número? Então você precisaria fazer um `float(valor_pi_lido)` para isso. Agora, e se quiséssemos salvar a lista em arquivo? Veja só (e teste, se possível):\n", "\n", "```python\n", "# salvar lista_frutas em um arquivo txt\n", "with open(\"lista_frutas.txt\", \"w\") as f:\n", " f.write(str(lista_frutas))\n", "\n", "# ler lista_frutas de um arquivo txt\n", "with open(\"lista_frutas.txt\", \"r\") as f:\n", " lista_frutas_lida = f.read()\n", " print(f'{lista_frutas_lida}, tipo {type(lista_frutas_lida)}')\n", "```\n", "\n", "A mesma coisa: convertemos primeiro a lista para string para poder salvar (por isso o `str()` em `f.write(str(lista_frutas))`). E, para ler, também teremos o resultado em string, igualzinho como no exemplo anterior. Aqui, a saída será:\n", "\n", "```bash\n", "['maçã', 'banana', 'laranja', 'manga'], tipo \n", "```\n", "\n", "Também existe outra forma de salvar os dados dessa lista em arquivo. Poderíamos, por exemplo, salvar cada fruta em uma linha separada. Assim, teríamos o seguinte:\n", "\n", "```python\n", "# salvar lista_frutas em um arquivo txt\n", "with open(\"lista_frutas_split.txt\", \"w\") as f:\n", " for fruta in lista_frutas:\n", " f.write(fruta + \"\\n\")\n", "\n", "# ler lista_frutas de um arquivo txt\n", "with open(\"lista_frutas_split.txt\", \"r\") as f:\n", " lista_frutas_lida = f.readlines()\n", " print(f'{lista_frutas_lida}, tipo {type(lista_frutas_lida)}')\n", "```\n", "\n", "O primeiro `for` irá percorrer cada elemento da `lista_frutas` e escreverá cada elemento em uma linha separada no arquivo de texto. Já a linha `f.write(fruta + \"\\n\")` adiciona uma quebra de linha depois de cada fruta, para que cada uma fique em uma linha separada no arquivo.\n", "\n", "Outra mudança: viu a função `readlines()`? Ela lerá o arquivo linha por linha e retornará uma lista contendo cada linha como um elemento separado. Interessante, não é? Agora, e para salvarmos o dicionário? Poderíamos fazer o seguinte:\n", "\n", "```python \n", "# salvar dicionario_pessoas em um arquivo txt\n", "with open(\"dicionario_pessoas.txt\", \"w\") as f:\n", " f.write(str(dicionario_pessoas))\n", "\n", "# ler dicionario_pessoas de um arquivo txt\n", "with open(\"dicionario_pessoas.txt\", \"r\") as f:\n", " dicionario_pessoas_lido = f.read()\n", " print(f'{dicionario_pessoas_lido}, tipo {type(dicionario_pessoas_lido)}')\n", "```\n", "\n", "Aqui, a mesma coisa dos outros exemplos anteriores também acontece: convertemos o dicionário para texto, e lemos de volta um texto. É por isso que para guardarmos estruturas de dados um pouco mais complexas como um dicionário ou uma lista não seria muito interessante trabalhar com esse `read()` ou `readlines()` do jeito que são. Afinal, teríamos uma certa dor de cabeça para convertermos o resultado do arquivo lido (que é sempre em string) de volta para uma lista, um dicionário ou qualquer outra estrutura." ] }, { "cell_type": "markdown", "id": "4964199a-ab76-445f-9186-b2db06977a1a", "metadata": {}, "source": [ "### Salvando em JSON\n", "O JSON é outra maneira bem comum para salvarmos arquivos. Ele é usado para transmitir informações entre diferentes aplicações, permitindo que dados sejam facilmente compartilhados e manipulados. Geralmente sites, aplicativos e outros serviços que se comunicam com um usuário também trocam informações com servidores e bancos de dados usando JSON.\n", "\n", "Um arquivo JSON é composto por pares chave-valor, onde a chave é uma string que identifica o valor correspondente, que pode ser um número, string, objeto ou lista. Os objetos e listas podem ser aninhados, o que permite a criação de estruturas complexas de dados. Aqui, uma analogia para entender um arquivo JSON seria pensar em um mapa de cidade. Cada chave seria como uma rua, e seu valor correspondente seria como as casas ou prédios nessa rua. Assim como um mapa, um arquivo JSON fornece um meio organizado de acessar informações e entender a estrutura de um conjunto de dados.\n", "\n", "Sabe o dicionário em Python que você está acostumado (eu espero) a trabalhar? Então, está praticamente (senão totalmente) em formato JSON, já. Bom, vamos para os exemplos? Experimente rodar o código abaixo em Python:\n", "\n", "```python\n", "import json\n", "\n", "# INÍCIO DO BLOCO 1\n", "# salvar valor_pi em um arquivo json\n", "with open(\"valor_pi.json\", \"w\") as f:\n", " json.dump(valor_pi, f)\n", "\n", "# ler valor_pi de um arquivo json\n", "with open(\"valor_pi.json\", \"r\") as f:\n", " valor_pi_lido = json.load(f)\n", " print(f'{valor_pi_lido}, tipo {type(valor_pi_lido)}')\n", "# FIM DO BLOCO 1\n", "\n", "# INÍCIO DO BLOCO 2\n", "# salvar lista_frutas em um arquivo json\n", "with open(\"lista_frutas.json\", \"w\") as f:\n", " json.dump(lista_frutas, f)\n", "\n", "# ler lista_frutas de um arquivo json\n", "with open(\"lista_frutas.json\", \"r\") as f:\n", " lista_frutas_lido = json.load(f)\n", " print(f'{lista_frutas_lido}, tipo {type(lista_frutas_lido)}')\n", "# FIM DO BLOCO 2\n", "\n", "# INÍCIO DO BLOCO 3\n", "# salvar dicionario_pessoas em um arquivo json\n", "with open(\"dicionario_pessoas.json\", \"w\") as f:\n", " json.dump(dicionario_pessoas, f)\n", "\n", "# ler dicionario_pessoas de um arquivo json\n", "with open(\"dicionario_pessoas.json\", \"r\") as f:\n", " dicionario_pessoas_lido = json.load(f)\n", " print(f'{dicionario_pessoas_lido}, tipo {type(dicionario_pessoas_lido)}')\n", " for nome, idade in dicionario_pessoas_lido.items():\n", " print(nome, idade)\n", "# FIM DO BLOCO 3\n", "```\n", "\n", "Muito código? Calma, vou explicar. Tá vendo aquele `import json` na primeira linha? Este código é uma importação do módulo `json` em Python. O módulo `json` é utilizado para codificar e decodificar dados em formato JSON. Imagine estes módulos como se fossem itens adicionais de uma comida de um fast-food ou os itens opcionais de um carro: eles não vem \"de fábrica\", e você precisa \"pedir\" por este item. Existem vários módulos já integrados ao Python que fornecem funções úteis para lidar com tarefas comuns, como manipulação de arquivos, processamento de dados, matemática, networking, entre outras. Como nem sempre precisamos desses módulos em todo código, só os importamos quando realmente é necessário. Como *somente* agora estamos precisando trabalhar com o JSON, nós chamamos agora por esta importação.\n", "\n", "Percebe que temos ao longo do código o `json.dump()` e `json.load()` no lugar do `f.write()` e `f.read()`? Então: estas funções são específicas para salvarmos os dados em formato JSON e lermos de volta os dados que estão em JSON, respectivamente. A função `json.dump()` sempre recebe dois parâmetros: primeiro, o objeto a ser salvo. Depois, o arquivo onde ele deve ser salvo.\n", "\n", "Em seguida, o código lê cada um dos arquivos utilizando a função `json.load()`, que recebe como parâmetro o arquivo de onde os dados devem ser lidos. O bloco 1 salva e lê o valor da variável `valor_pi` em um arquivo JSON (experimente abrir o arquivo `valor_pi.json` no bloco de notas depois de rodar este código). O bloco 2 salva e lê a lista de frutas `lista_frutas`. Por fim, o bloco 3 salva e lê o dicionário `dicionario_pessoas`, que é impresso na tela utilizando um `for`.\n", "\n", "O resultado desse código será isto:\n", "\n", "```bash\n", "3.14159, tipo \n", "['maçã', 'banana', 'laranja', 'manga'], tipo \n", "{'João': 25, 'Maria': 30, 'Pedro': 20, 'Marcos': 15}, tipo \n", "João 25\n", "Maria 30\n", "Pedro 20\n", "Marcos 15\n", "```\n", "\n", "Percebeu que os tipos estão corretos? Temos `float`, `list` e `dict`. Legal, né? Isto acontece porque a função `json.load()` já converte automaticamente os dados lidos para o formato Python correspondente." ] }, { "cell_type": "markdown", "id": "c98009d7-5fb5-4e43-a478-85489973e1d3", "metadata": {}, "source": [ "### Salvando em Pickle\n", "Beleza, mas e se quiséssemos salvar as variáveis do Python direto em um arquivo? Isto é: sem ser salvo em texto ou algo assim? E se quiséssemos salvar um dicionário como tal, ou uma lista do jeito que está, sem termos que nos preocupar em converter nada? É para resolver isso que temos em Python os arquivos pickle. Imagine que este pickle é como se fosse um pote de vidro onde podemos guardar alimentos na geladeira. Quando colocamos alimentos no pote, eles são armazenados em um formato que pode ser facilmente recuperado posteriormente, quando quisermos consumi-los. Assim como podemos armazenar diferentes tipos de alimentos em potes de vidro, podemos armazenar diferentes tipos de objetos Python em arquivos pickle.\n", "\n", "Arquivos pickle em Python são arquivos binários usados para serializar e desserializar objetos Python. Isso significa que podemos usar o formato pickle para converter objetos Python em uma sequência de bytes, que pode ser gravada em um arquivo, transmitida pela rede ou armazenada em um banco de dados, por exemplo. Posteriormente, podemos recuperar o objeto Python original a partir dos bytes usando a desserialização.\n", "\n", "Mas, e aí? Vamos testar?\n", "\n", "```python\n", "import pickle\n", "\n", "# INÍCIO DO BLOCO 1\n", "# salvar valor_pi em um arquivo pickle\n", "with open(\"valor_pi.pickle\", \"wb\") as f:\n", " pickle.dump(valor_pi, f)\n", "\n", "# ler valor_pi de um arquivo pickle \n", "with open(\"valor_pi.pickle\", \"rb\") as f:\n", " valor_pi_lido = pickle.load(f)\n", " print(f'{valor_pi_lido}, tipo {type(valor_pi_lido)}')\n", "# FIM DO BLOCO 1\n", "\n", "# INÍCIO DO BLOCO 2\n", "# salvar lista_frutas em um arquivo pickle\n", "with open(\"lista_frutas.pickle\", \"wb\") as f:\n", " pickle.dump(lista_frutas, f)\n", "\n", "# ler lista_frutas de um arquivo pickle\n", "with open(\"lista_frutas.pickle\", \"rb\") as f:\n", " lista_frutas_lida = pickle.load(f)\n", " print(f'{lista_frutas_lida}, tipo {type(lista_frutas_lida)}')\n", "# FIM DO BLOCO 2\n", "\n", "# INÍCIO DO BLOCO 3\n", "# salvar dicionario_pessoas em um arquivo pickle\n", "with open(\"dicionario_pessoas.pickle\", \"wb\") as f:\n", " pickle.dump(dicionario_pessoas, f)\n", "\n", "# ler dicionario_pessoas de um arquivo pickle\n", "with open(\"dicionario_pessoas.pickle\", \"rb\") as f:\n", " dicionario_pessoas_lido = pickle.load(f)\n", " print(f'{dicionario_pessoas_lido}, tipo {type(dicionario_pessoas_lido)}')\n", " for nome, idade in dicionario_pessoas_lido.items():\n", " print(nome, idade)\n", "# FIM DO BLOCO 3\n", "```\n", "\n", "O código acima terá o mesmo resultado do que fizemos com o exemplo do JSON, mas a diferença é que agora estamos trabalhando com pickle. Agora, importamos o módulo `pickle` na primeira linha porque, afinal de contas, estaremos trabalhando com arquivos pickle. O que temos também de diferenças são:\n", "- A abertura e escrita de arquivos com o `open()` deixou de usar os modos `\"w\"` e `\"r\"` para usar `\"wb\"` e `\"rb\"`. A letra `b` indica que estamos trabalhando com arquivos binários (ou seja: não é mais um arquivo de texto. Se você tentar abrir este arquivo pickle com o bloco de notas verá que não conseguirá entender nada).\n", "- Para salvar um arquivo `pickle` passamos a usar o `pickle.dump()`.\n", "- Para ler o conteúdo de um arquivo `pickle` passamos a usar o `pickle.load()`.\n", "\n", "Agora, quando preferimos usar JSON e quando pickle é melhor? A resposta é: *depende*. Se estivermos trabalhando com diferentes softwares, plataformas e linguagens de programação a resposta é clara: JSON. Se precisar abrir no bloco de notas/Visual Studio Code/similares, também seria o JSON. Agora, se a ideia é salvar uma variável dentro do seu computador para você continuar trabalhando depois em Python, aí seria pickle. Dito isso, não recomendo muito que você use pickle para transferir variáveis de lugares desconhecidos para você ou vice-versa: você pode estar carregando uma variável contendo algo que pode causar danos para o seu código ou para outros computadores sem querer." ] }, { "cell_type": "markdown", "id": "f62b8572-22ce-4bbc-a4a2-8144f8dcbab1", "metadata": {}, "source": [ "## Exercícios\n", "Vamos colocar em prática os conhecimentos de manipulação de arquivos? Iremos também combinar com o conhecimento de listas e dicionários do último capítulo. Vamos lá?\n", "\n", "1. Crie um dicionário com o nome e a profissão de duas pessoas e adicione uma terceira pessoa com nome e profissão. Salve o resultado em um arquivo JSON.\n", "2. Crie um código que peça para o usuário digitar uma frase. Salve o resultado em uma arquivo de texto. Depois, abra este arquivo de texto que salvou e mostre o resultado na tela.\n", "3. A partir do exercício 2 e após mostrar o resultado na tela, peça novamente para que o usuário digite uma nova frase. Adicione esta nova frase no mesmo arquivo de texto sem apagar o conteúdo que já estava lá, e mostre o resultado na tela.\n", "4. Crie uma lista com números de 1 a 10 e, em seguida, crie uma segunda lista contendo somente os números pares. Salve somente a lista dos números pares em um arquivo pickle. Depois, abra novamente o arquivo pickle que salvou e mostre na tela o seu conteúdo.\n", "5. Modifique o código do exercício 4 para que salve, dentro de um único arquivo, as duas listas. Depois, abra novamente o arquivo pickle que salvou e mostre na tela o seu conteúdo." ] }, { "cell_type": "markdown", "id": "6eb1958e-d357-4e03-9e7c-17f34c05a5ee", "metadata": {}, "source": [ "### Respostas" ] }, { "cell_type": "markdown", "id": "647c363c-7e02-45f9-b31f-b354b28fcaad", "metadata": {}, "source": [ "**1. Crie um dicionário com o nome e a profissão de duas pessoas e adicione uma terceira pessoa com nome e profissão. Salve o resultado em um arquivo JSON.**\n", "\n", "Você deve ter percebido que é praticamente o mesmo exercício do capítulo anterior, mas com um passo final para salvar o resultado em JSON, não é? Veja só como ficaria um exemplo de resposta:\n", "\n", "```python\n", "import json\n", "\n", "pessoas = {}\n", "\n", "# adiciona as duas primeiras pessoas\n", "for i in range(2):\n", " nome = input(\"Digite o nome da pessoa: \")\n", " profissao = input(\"Digite a profissão da pessoa: \")\n", " pessoas[nome] = profissao\n", "\n", "# adiciona a terceira pessoa\n", "nome = input(\"Digite o nome da terceira pessoa: \")\n", "profissao = input(\"Digite a profissão da terceira pessoa: \")\n", "pessoas[nome] = profissao\n", "\n", "# salva o resultado em um arquivo JSON\n", "with open(\"pessoas.json\", \"w\") as arquivo:\n", " json.dump(pessoas, arquivo)\n", "```\n", "\n", "O que temos de diferente neste código? Veja que, primeiramente, importamos a biblioteca `json` na primeira linha do Python para salvar o dicionário `pessoas` em um arquivo JSON. A função `json.dump()` é usada para escrever o dicionário no arquivo JSON. E, ainda, a opção `\"w\"` é passada para o `open()` para indicar que queremos escrever no arquivo.\n", "\n", "Experimente testar o código e abrir o arquivo `pessoas.json` logo em seguida para ver o que houve. No meu caso, o meu arquivo ficou assim:\n", "\n", "```json\n", "{\"João\": \"Engenheiro\", \"Maria\": \"Advogada\", \"Pedro\": \"Médico\"}\n", "```" ] }, { "cell_type": "markdown", "id": "951f4884-8fc6-468c-a82d-04408c910e9e", "metadata": {}, "source": [ "**2. Crie um código que peça para o usuário digitar uma frase. Salve o resultado em uma arquivo de texto. Depois, abra este arquivo de texto que salvou e mostre o resultado na tela.**\n", "\n", "```python\n", "# pede para o usuário digitar uma frase\n", "frase = input(\"Digite uma frase: \")\n", "\n", "# salva a frase em um arquivo de texto\n", "with open(\"frase.txt\", \"w\") as arquivo:\n", " arquivo.write(frase)\n", "\n", "# abre o arquivo de texto e exibe o conteúdo na tela\n", "with open(\"frase.txt\", \"r\") as arquivo:\n", " conteudo = arquivo.read()\n", " print(\"Conteúdo do arquivo:\")\n", " print(conteudo)\n", "```\n", "\n", "Veja que a função `input()` para solicitar que o usuário digite uma frase. Em seguida, a salvamos em um arquivo de texto chamado `frase.txt` usando a abertura do arquivo em modo de escrita (`\"w\"`) e a função `write()`.\n", "\n", "Depois, abrimos o arquivo em modo de leitura (`\"r\"`) e o conteúdo é lido usando o método `read()` e salvo na variável `conteudo`, que é mostrada na tela com o `print(conteudo)`." ] }, { "cell_type": "markdown", "id": "9fb3517a-a91f-4de1-824e-a7b4d24114c7", "metadata": {}, "source": [ "**3. A partir do exercício 2 e após mostrar o resultado na tela, peça novamente para que o usuário digite uma nova frase. Adicione esta nova frase no mesmo arquivo de texto sem apagar o conteúdo que já estava lá, e mostre o resultado na tela.**\n", "\n", "```python\n", "# pede para o usuário digitar uma frase\n", "frase = input(\"Digite uma frase: \")\n", "\n", "# salva a frase em um arquivo de texto\n", "with open(\"frase.txt\", \"w\") as arquivo:\n", " arquivo.write(frase)\n", "\n", "# abre o arquivo de texto e exibe o conteúdo na tela\n", "with open(\"frase.txt\", \"r\") as arquivo:\n", " conteudo = arquivo.read()\n", " print(\"Conteúdo do arquivo:\")\n", " print(conteudo)\n", "\n", "# Pede ao usuário para digitar uma outra frase\n", "frase = input(\"Digite uma frase: \")\n", "\n", "# Abre o arquivo em modo \"a\" para adicionar a nova frase\n", "with open(\"frases.txt\", \"a\") as arquivo:\n", " # Adiciona a nova frase ao arquivo\n", " arquivo.write(frase + \"\\n\")\n", "\n", "# Abre o arquivo novamente em modo \"r\" (leitura)\n", "with open(\"frases.txt\", \"r\") as arquivo:\n", " # Lê o conteúdo do arquivo e mostra na tela\n", " conteudo = arquivo.read()\n", " print(conteudo)\n", "```\n", "\n", "Perceba principalmente o que vem depois do comentário *\"Pede ao usuário para digitar uma outra frase\"*. Para adicionar a nova frase ao arquivo de texto sem apagar o conteúdo já existente, usamos o modo `\"a\"` (append) na abertura do arquivo. Se usássemos o `\"w\"` de volta iríamos sobrescrever o que já havia sido salvo anteriormente." ] }, { "cell_type": "markdown", "id": "2b0598cc-bc20-41b8-bf89-177a84b66a9e", "metadata": {}, "source": [ "**4. Crie uma lista com números de 1 a 10 e, em seguida, crie uma segunda lista contendo somente os números pares. Salve somente a lista dos números pares em um arquivo pickle. Depois, abra novamente o arquivo pickle que salvou e mostre na tela o seu conteúdo.**\n", "\n", "```python\n", "import pickle\n", "\n", "# cria a lista de números de 1 a 10\n", "numeros = list(range(1, 11))\n", "\n", "# filtra os números pares\n", "numeros_pares = []\n", "for num in numeros:\n", " if num % 2 == 0:\n", " numeros_pares.append(num)\n", "\n", "# salva a lista de números pares em um arquivo pickle\n", "with open(\"numeros_pares.pickle\", \"wb\") as f:\n", " pickle.dump(numeros_pares, f)\n", "\n", "# abre o arquivo pickle e mostra o conteúdo na tela\n", "with open(\"numeros_pares.pickle\", \"rb\") as f:\n", " numeros_pares_lidos = pickle.load(f)\n", " print(numeros_pares_lidos)\n", "```\n", "\n", "Veja que salvamos a lista `numeros_pares` em um arquivo pickle chamado `numeros_pares.pickle`. Como é um arquivo binário (isto é: não é legível por humanos ao abrir no bloco de notas), salvamos este arquivo usando `\"wb\"` e lemos usando `\"rb\"` (perceba a letra `b` presente em ambos os casos). Por fim, o código abre novamente o arquivo pickle com o uso do `pickle.load()` e mostra o conteúdo na tela. O resultado esperado é a exibição na tela da lista `[2, 4, 6, 8, 10]`." ] }, { "cell_type": "markdown", "id": "c54e72b7-8467-4f7f-ae8c-257be0af5ef6", "metadata": {}, "source": [ "**5. Modifique o código do exercício 4 para que salve, dentro de um único arquivo, as duas listas. Depois, abra novamente o arquivo pickle que salvou e mostre na tela o seu conteúdo.**\n", "\n", "```python\n", "import pickle\n", "\n", "# cria a lista de números de 1 a 10\n", "numeros = list(range(1, 11))\n", "\n", "# filtra os números pares\n", "numeros_pares = []\n", "for num in numeros:\n", " if num % 2 == 0:\n", " numeros_pares.append(num)\n", "\n", "# salva a lista de números pares em um arquivo pickle\n", "with open(\"numeros_pares.pickle\", \"wb\") as f:\n", " pickle.dump([numeros, numeros_pares], f)\n", "\n", "# abre o arquivo pickle e mostra o conteúdo na tela\n", "with open(\"numeros_pares.pickle\", \"rb\") as f:\n", " numeros_lidos, numeros_pares_lidos = pickle.load(f)\n", " print(numeros_lidos)\n", " print(numeros_pares_lidos)\n", "```\n", "\n", "É muito provável que você tenha dificuldades para fazer este aqui. Afinal, em nenhum momento lhe disse como salvaríamos mais de uma variável em um arquivo pickle. Sem problemas - a ideia aqui é a de demonstrar, mesmo. Perceba duas grandes modificações em relação ao código anterior:\n", "- O `pickle.dump([numeros, numeros_pares], f)`: veja o `[numeros, numeros_pares]`. Para salvar mais de uma variável em um mesmo arquivo pickle basta informar todas as variáveis em uma lista.\n", "- Para ler estas variáveis, basta informar a mesma quantidade na hora de chamar o `pickle.load()`. Como salvamos duas variáveis, teremos que armazenar o resultado do `pickle.load()` em duas variáveisl. É por isso que temos o `numeros_lidos, numeros_pares_lidos` na antepenúltima linha." ] }, { "cell_type": "markdown", "id": "67c56eb3-a5ea-4b5a-9f8f-adf4b3d70696", "metadata": {}, "source": [ "## Referências bibliográficas" ] }, { "cell_type": "markdown", "id": "e1aacf96-ae08-482a-9ba7-24bf0280151f", "metadata": {}, "source": [ "- PYTHON. CSV File Reading and Writing. Disponível em: https://docs.python.org/3/library/csv.html. Acesso em: 14 mar. 2023.\n", "- PYTHON. JSON - JavaScript Object Notation. Disponível em: https://docs.python.org/3/library/json.html. Acesso em: 14 mar. 2023.\n", "- PYTHON. pickle — Python object serialization. Disponível em: https://docs.python.org/3/library/pickle.html. Acesso em: 14 mar. 2023.\n", "- PYTHON. Tutorial de Python 3.9.6rc1. Disponível em: https://docs.python.org/pt-br/3/tutorial/index.html. Acesso em: 14 mar. 2023.\n", "- GEEKSFORGEEKS. JSON with Python. Disponível em: https://www.geeksforgeeks.org/json-with-python/. Acesso em: 14 mar. 2023.\n", "- GEEKSFORGEEKS. Reading CSV files in Python. Disponível em: https://www.geeksforgeeks.org/reading-csv-files-in-python/. Acesso em: 14 mar. 2023.\n", "- JSON.org. Introducing JSON. Disponível em: https://www.json.org/json-en.html. Acesso em: 14 mar. 2023.\n", "- W3SCHOOLS. Python File Handling. Disponível em: https://www.w3schools.com/python/python_file_handling.asp. Acesso em: 14 mar. 2023." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" } }, "nbformat": 4, "nbformat_minor": 5 }