Exercícios da aula 06
Exercícios da aula 06: Arquivos¶
Na aula 06, terminamos as funções e introduzimos a escrita e leitura de arquivos. Os exercícios referentes a funções já foram resolvidos junto com os exercícios da aula 05.
Exercício 1¶
Escreva um programa que receba o nome de um arquivo pela linha de comando e imprimia todas as linhas desse aqruivo
O programa pode ser visto no arquivo exercicio01.py:
#! /usr/bin/env python3
import sys
def imprimir_linhas(arquivo):
with open(arquivo, "r") as arq:
for linha in arq.readlines():
print(linha.strip())
if __name__ == '__main__':
arquivo = sys.argv[1]
imprimir_linhas(arquivo)
Para se executar o script acima, pode-se fazer o seguinte:
pjabardo@makhno> python3 exercicio01.py arquivo-ex01.txt
Primeira linha
Segunda
Terceira
...
Última linha
pjabardo@makhno:~/Documents/assipt/pythonassipt/06-aula$
Essa solução vai funcionar tanto no Windows quanto no Linux ou MacOS ou qualquer Unix.
Script como executável no Linux (e MacOS?)¶
Muitas vezes é conveniente usar o script python como se fosse um programa executável executável (.exe no windows). A linha #! /usr/bin/env python3
é para especificar, no unix (linux, macos) qual o interpretador que deve ser usado. Para que seja usado como executável, ainda é preciso avisar o sistema operacional para tratar o arquivo como executável:
pjabardo@makhno> chmod +x exercicio01.py
Script como executável no Windows¶
É bem parecido com o Linux mas na primeira linha deve-se substituir #! /usr/bin/env python3
por #!"C:\Python39\Python.exe"
. Ajuste para o caminho do executável do Python que tem no teu sistema.
Executando o script "executável":¶
pjabardo@makhno> ./exercicio01.py arquivo-ex01.txt
Primeira linha
Segunda
Terceira
...
Última linha
imprimir_linhas("arquivo-ex01.txt")
Observe que nessa solução, a funcionalidade está implementada dentro da função imprimir_linhas
. Com isso, podemos reutilizar o código. É por isso que existe o trecho
if __name__ == '__main__':
arquivo = sys.argv[1]
imprimir_linhas(arquivo)
Caso o if
seja verdadeiro, vamos executar essa trecho. Esse if
é verdadeiro se estamos usando o arquivo como um script.
O arquivo também pode ser usado como um módulo. E aí que vem a vantagem de escrever este programa desse jeito:
# Usando o programa como um módulo:
from exercicio02 import imprimir_linhas
imprimir_linhas("arquivo-ex01.txt")
A idéia é sempre tentar reaproveitar código o máximo possível!
Exercício 2¶
Modifique o programa do exercício de tal modo que receba mais dois parâmetros: a linha de incício e a de fim de impressão. O programa deve imprimir apenas as linhas entre esses dois valores (inlcuindo as linhas de incício e fim)
A minha solução pode ser vista a seguir. Ela se encontra no arquivo exercicio02.py
e tem algumas novidades.
import argparse
def imprimir_linhas(arquivo, linha_inicio=0, linha_fim=-1):
with open(arquivo, "r") as arq:
i = 0
for linha in arq:
if i >= linha_inicio and (linha_fim < 0 or i < linha_fim):
print(linha.strip())
i = i + 1
if i == linha_fim:
break
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Imprimir linhas")
parser.add_argument('arquivo', help="Nome do arquivo", type=str, nargs=1)
parser.add_argument("-i", "--inicio", help="Número da primeira linha para imprimir 0 caso não seja fornecido.", default=0, type=int)
parser.add_argument("-f", "--fim", help="Número da última que deve ser impressa. -1 para imprimir até o final", default=-1, type=int)
args = parser.parse_args()
imprimir_linhas(args.arquivo[0], args.inicio, args.fim)
A estrutura do código é a mesma que o programa do programa anterior. Temos uma função que implementa a funcionalidade que desejamos (função imprimir_linhas
) e temos o trecho
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Imprimir linhas")
# ...
Assim o código pode ser usado como módulo e como script (programa).
A primeira novidade é que o programa usa o módulo argparse
da biblioteca padrão do Python. Este módulo ajuda a interpretar os argumentos de linha de comando. É muito melhor do que usar sys.argv
diretamente como fizemos no exercício 01.
Vejamos a funcionalidade do código:
pjabardo@makhno> ./exercicio02.py --help
usage: exercicio02.py [-h] [-i INICIO] [-f FIM] arquivo
Imprimir linhas
positional arguments:
arquivo Nome do arquivo
optional arguments:
-h, --help show this help message and exit
-i INICIO, --inicio INICIO
Número da primeira linha para imprimir 0 caso não seja fornecido.
-f FIM, --fim FIM Número da última que deve ser impressa. -1 para imprimir até o final
Ao usar o módulo argparse
já temos um help! Como funciona? Primeiro é necessário criar o parser que vai interpretar as opções. O parser é inicializado na linha
parser = argparse.ArgumentParser(description="Imprimir linhas")
A descrição (description
) é o que aparece no help. Aí temos que definir os argumentos de linha de comando. O jeito que eu fiz o programa, temos que fornecer o nome de um arquivo e isso é implementado na linha
parser.add_argument('arquivo', help="Nome do arquivo", type=str, nargs=1)
Teremos um argumento chamado arquivo
que é do tipo str
e é composto por apenas um argumento (nargs=1
).
Para dizer em que linha se deve começar a imprimir, usa-se a opção --inicio
ou -i
definido na linha
parser.add_argument("-i", "--inicio", help="Número da primeira linha para imprimir 0 caso não seja fornecido.", default=0, type=int)
O argumento especificando a linha inicial que deve ser impressa é opcional tem duas formas: a curta -i
ou a extensa --inicio
. O tipo de dado vai ser um int
e caso este argumento não seja fornecido, o valor usado é 0 (começamos da primeir linha).
O argumento especificando a linha final que deve ser impressa é também opcional. Neste caso, se nada for escrito, o valor -1 -e adotado. Este valor sinaliza que queremos imprimir até o final.
parser.add_argument("-f", "--fim", help="Número da última que deve ser impressa. -1 para imprimir até o final", default=-1, type=int)
A linha seguinte:
args = parser.parse_args()
aplica o parser que definimos aos argumentos de linha de comando (sys.argv
).
Para acessar os argumentos, basta usar os campos de args
:
-
args.arquivo
para o nome do arquivo -
args.inicio
para o número de linha inicial -
args.fim
para o número de linha final.
Esses argumentos são então passados para a função imprimir_linhas
(vamos destrinchar mais adiante).
Vamos ver como funciona:
Se não fornecermos nenhuma opção, ocorre um erro:
pjabardo@makhno> ./exercicio02.py
usage: exercicio02.py [-h] [-i INICIO] [-f FIM] arquivo
exercicio02.py: error: the following arguments are required: arquivo
pjabardo@makhno:~/Documents/assipt/pythonassipt/06-aula$
Fornecendo apenas o nome do arquivo, imprimimos todas as linhas.
pjabardo@makhno> ./exercicio02.py arquivo-ex01.txt
Primeira linha
Segunda
Terceira
...
Última linha
Só a opção -i
:
pjabardo@makhno> ./exercicio02.py -i1 arquivo-ex01.txt
Segunda
Terceira
...
Última linha
pode ser também
pjabardo@makhno> ./exercicio02.py --inicio 2 arquivo-ex01.txt
Terceira
...
Última linha
Nos exemplos acima, -f
ou --fim
fornecem o valor padrão -1 que representa imprimir até o final do arquivo
pjabardo@makhno> ./exercicio02.py --inicio 2 --fim 4 arquivo-ex01.txt
Terceira
...
ou
pjabardo@makhno> ./exercicio02.py -i 1 -f 3 arquivo-ex01.txt
Segunda
Terceira
Observe que o parser vai ver se o tipo é compatível:
pjabardo@makhno> ./exercicio02.py -i um
usage: exercicio02.py [-h] [-i INICIO] [-f FIM] arquivo
exercicio02.py: error: argument -i/--inicio: invalid int value: 'um'
Olha que legal: reconheceu que um
não é um número e deu erro!
Vamos analisar agora o código em si que tem algumas coisas interessantes.
def imprimir_linhas(arquivo, linha_inicio=0, linha_fim=-1):
with open(arquivo, "r") as arq:
i = 0
for linha in arq:
if i >= linha_inicio and (linha_fim < 0 or i < linha_fim):
print(linha.strip())
i = i + 1
if i == linha_fim:
break
A função tem três argumentos:
-
arquivo
uma string com o nome dos arquivos -
linha_inicio
um argumento opcional com valor padrão 0 que indica a primeira linha a ser impressa -
linha_fim
um argumento opcional que indica a última linha a ser impressa. Se for -1, imprime até o final
O código usa with open(arquivo, "r") as arq
para abrir o arquivo para leitura, como a maioria dos programas até agora.
Agora que as coisas são um pouco diferentes. Até agora usamos o método arq.readlines()
que lê todas as linhas de um arquivo. Prático e útil mas e se o arquivo for gigantesco e precisamos só de algumas linhas no começo? Vamos gastar um monte de memória para nada.
Uma opção é usar o método arq.readline()
que lê uma linha de cada vez. Mas existe uma possibilidade mais interessante: usar o o tipo arquivo como um iterador. Aí acessamos diretamente no for
linha a linha. Temos um contador i
para contar as linhas já lidas e só imprimimos quando i >= linha_inicio
.
Agora temos que ter cuidado para acabar a impressão. Temos dois casos:
-
linha_fim < 0
Vamos até o final do arquivo -
linha_fim >= 0
vamos contar até chegar nesse limite.
Exercício 3¶
Crie um programa que receba o nome de dois arquivos como parâmetros da linha de comando e que gere um arquivo de saída com as linhas do primeiro e do segundo arquivo
Não vou fazer um programa, apenas uma função:
def imprime_arquivos(arquivos_entrada, arquivo_saída):
with open(arquivo_saída, "w") as fout:
for arq in arquivos_entrada:
with open(arq, "r") as fin:
for linha in fin:
fout.write(linha)
imprime_arquivos(["arquivo-ex01.txt", "outro-arquivo.txt"], "saida-exercicio-03.txt")
O resultado pode ser visto a seguir:
Primeira linha
Segunda
Terceira
...
Última linha
Outra linha
Mais outra
Mais um montão de linhas
A última linha
Exercício 4¶
Crie um programa que recebe o nome de um arquivo e o nome do arquivo de saída e que inverta as linhas do primeiro arquivo e armazene no segundo.
Novamente não vou fazer o programa, apenas uma função.
def reverter_arquivo(arquivo_entrada, arquivo_saída):
with open(arquivo_entrada, "r") as fin:
linhas = fin.readlines()
linhas.reverse()
with open(arquivo_saída, "w") as fout:
for linha in linhas:
fout.write(linha)
reverter_arquivo("arquivo-ex01.txt", "arquivo-reverso.txt")
A solução acima é simples mas imagina se você tiver arquivos enormes que não cabem na memória. É possível arranjar soluções optimizadas para estes casos mas não é tão simples assim. Você consegue imaginar por quê?
Última linha
...
Terceira
Segunda
Primeira linha
Exercício 5¶
Modofique o programa anterior para utilizar o elemento p
em vez de h2
Vou criar uma função que encapsula tudo isso. O tipo de elemento pode ser fornecido pelo usuário.
filmes = {
"drama" : ["O Homem Elefante", "O Poderoso Chefão"],
"comédia" : ["Se beber não case", "O Auto da Compadecida", "American Pie"],
"policial" : ["Seven", "O silêncio dos inocentes", "Os Homens que não Amavam as Mulheres"],
"guerra" : ["Stalingrado", "O Resgate do Soldado Ryan", "Dunquerque"],
"ficção científica" : ["O Expresso do Amanhã", "Duna", "Guerra nas Estrelas", "A Ira de Kahn"]
}
def filmes_html(filmes, arquivo="filmes.html", elemento="p"):
with open(arquivo, "w", encoding="utf-8") as página:
página.write("""
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<title>Filmes</title>
</head>
<body>
""")
for c,v in filmes.items():
página.write(f"<h1>{c.capitalize()}</h1>\n")
for e in v:
página.write(f"<{elemento}>{e}</{elemento}>\n")
página.write("""
</body>
</html>
""")
filmes_html(filmes, "filmes-p.html", elemento="p")
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<title>Filmes</title>
</head>
<body>
<h1>Drama</h1>
<p>O Homem Elefante</p>
<p>O Poderoso Chefão</p>
<h1>Comédia</h1>
<p>Se beber não case</p>
<p>O Auto da Compadecida</p>
<p>American Pie</p>
<h1>Policial</h1>
<p>Seven</p>
<p>O silêncio dos inocentes</p>
<p>Os Homens que não Amavam as Mulheres</p>
<h1>Guerra</h1>
<p>Stalingrado</p>
<p>O Resgate do Soldado Ryan</p>
<p>Dunquerque</p>
<h1>Ficção científica</h1>
<p>O Expresso do Amanhã</p>
<p>Duna</p>
<p>Guerra nas Estrelas</p>
<p>A Ira de Kahn</p>
</body>
</html>
filmes_html(filmes, "filmes-h2.html", elemento="h2")
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<title>Filmes</title>
</head>
<body>
<h1>Drama</h1>
<h2>O Homem Elefante</h2>
<h2>O Poderoso Chefão</h2>
<h1>Comédia</h1>
<h2>Se beber não case</h2>
<h2>O Auto da Compadecida</h2>
<h2>American Pie</h2>
<h1>Policial</h1>
<h2>Seven</h2>
<h2>O silêncio dos inocentes</h2>
<h2>Os Homens que não Amavam as Mulheres</h2>
<h1>Guerra</h1>
<h2>Stalingrado</h2>
<h2>O Resgate do Soldado Ryan</h2>
<h2>Dunquerque</h2>
<h1>Ficção científica</h1>
<h2>O Expresso do Amanhã</h2>
<h2>Duna</h2>
<h2>Guerra nas Estrelas</h2>
<h2>A Ira de Kahn</h2>
</body>
</html>
Exercício 6¶
Modofique o programa 9.8 para gerar uma lista html usando os elementos ul
e li
. Todos os elementos da lista devem estar dentro do elemento ul
e cada item dentro de um elemento li
. Exemplo:
<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>
def filmes_html_item(filmes, arquivo="filmes.html"):
with open(arquivo, "w", encoding="utf-8") as página:
página.write("""
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<title>Filmes</title>
</head>
<body>
""")
for c,v in filmes.items():
página.write(f"<h1>{c.capitalize()}</h1>\n")
página.write(f"<ul>")
for e in v:
página.write(f"<li>{e}</li>\n")
página.write(f"</ul>")
página.write("""
</body>
</html>
""")
filmes_html_item(filmes, "filmes-li.html")
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<title>Filmes</title>
</head>
<body>
<h1>Drama</h1>
<ul><li>O Homem Elefante</li>
<li>O Poderoso Chefão</li>
</ul><h1>Comédia</h1>
<ul><li>Se beber não case</li>
<li>O Auto da Compadecida</li>
<li>American Pie</li>
</ul><h1>Policial</h1>
<ul><li>Seven</li>
<li>O silêncio dos inocentes</li>
<li>Os Homens que não Amavam as Mulheres</li>
</ul><h1>Guerra</h1>
<ul><li>Stalingrado</li>
<li>O Resgate do Soldado Ryan</li>
<li>Dunquerque</li>
</ul><h1>Ficção científica</h1>
<ul><li>O Expresso do Amanhã</li>
<li>Duna</li>
<li>Guerra nas Estrelas</li>
<li>A Ira de Kahn</li>
</ul>
</body>
</html>
Comentários
Comments powered by Disqus