MAC0216 - Técnicas de Programação I
tuple
)¶Uma tupla (tuple
) em Python é uma sequência imutável de valores de qualquer tipo.
Para criar uma tupla, lista-se uma sequência de valores separados por vírgulas e, opcionalmente, entre parênteses.
Tuplas são úteis para representar registros (mas sem atribuir nomes aos campos). Um registro é uma coleção de valores relacionados. Num registro representado como uma tupla, é a posição do valor dentro da tupla que determina o seu significado.
aluno1 = (18632827, "John Lennon", 19, "Bacharelado em Ciência da Computação") # primeira tupla
aluno2 = 19817271, "Ringo Star", 21, "Licenciatura em Matemática" # segunda tupla (sem parênteses!)
print("Primeira tupla: ", aluno1, "Tipo: ", type(aluno1))
print("Segunda tupla: ", aluno2, "Tipo: ", type(aluno2))
print("Tamanho da primeira tupla: ", len(aluno1))
print("Valor de uma posição da primeira tupla: ", aluno1[1])
print("Uma fatia da segunda tupla: ", aluno2[1:3])
print("Todos os elementos da segunda tupla: ")
for elemento in aluno2:
print(elemento)
Como em qualquer tipo de sequência em Python, numa tupla t
podemos aplicar as operações de indexação(t[i]
) , fatiamento (t[i:j:k]
), obtenção do comprimento (len(t)
), verificação de pertinência (x in t
ou x not in t
), percorrimento com laço (for x in t
), concatenação (t + s
), replicação (t * n
) obtenção do valor mínimo (min(t)
) e máximo (max(t)
), entre outras.
Mas como tuplas são sequências imutáveis (assim como as strings), não podemos aplicar nelas operações de modificação da sequência, como a atribuição de um valor para uma posição ou a adição de um novo valor à sequência. Veja no exemplo a seguir o erro gerado na tentativa de atribuição de um valor à uma posição de uma tupla:
aluno = (18632827, "John Lennon", 19, "Bacharelado em Ciência da Computação") # (NUSP, Nome, Idade, Curso)
aluno[1] = "Ringo Star"
Python tem um mecanismo de atribuição de tuplas que nos permite atribuir os valores de uma tupla (à direita do operador de atribuição =
) para uma tupla de variáveis (à esquerda do =
), como ilustrado no exemplo abaixo:
aluno = (18632827, "John Lennon", 19, "Bacharelado em Ciência da Computação")
nusp, nome, idade, curso = aluno # atribuição de tupla
print("NUSP: ", nusp)
print("Nome: ", nome)
print("Idade:", idade)
print("Curso:", curso)
Observe que, na atribuição do exemplo acima, acontece um "desempacotamento" dos valores em aluno
, para a atribuição para as variáveis do lado esquerdo do operador =
.
Também é possível fazer esse "desempacotamento" de tuplas em laços for ... in ...
:
alunos = [("Paul", 19), ("Ringo", 21), ("John", 18)] # lista de tuplas de alunos
for nome_aluno, idade_aluno in alunos:
print(nome_aluno, idade_aluno)
Usando a atribuição de tuplas, é possível escrever a troca dos valores de duas variáveis de uma forma bem elegante:
x = 10
y = 20
print("Antes da troca: x = %d, y = %d" %(x,y))
x,y = y,x # troca os valores de x e y
print("Depois da troca: x = %d, y = %d" %(x,y))
Em outras linguagens de programação, seria preciso usar uma variável auxiliar para efetuar a troca:
x = 10
y = 20
print("Antes da troca: x = %d, y = %d" %(x,y))
aux = x
x = y
y = aux
print("Depois da troca: x = %d, y = %d" %(x,y))
Nesses dois últimos exemplos, é interessante observar também que o operador de formatação de strings %
(que está sendo usado para criar a string passada para a função print()
) "entende" tuplas e trata cada elemento nelas como um campo separado.
Tuplas também são usadas quando se quer devolver mais de um valor no return
de uma função. Veja o exemplo abaixo:
import math
def infosCirculo(r):
""" (numero) -> (float,float)
Recebe um número r e retorna a circunferência
e a área do círculo de raio r.
"""
circunferencia = 2 * math.pi * r
area = math.pi * r * r
return (circunferencia, area)
c, a = infosCirculo(10)
print(c, a)
namedtuple
)¶Uma tupla nomeada funciona como as tuplas que vimos nos exemplos acima, mas tem uma facilidade adicional: a possibilidade de se acessar os seus campos por meio de nomes atribuídos a eles.
Para criar tuplas nomeadas, é preciso importar a classe namedtuple
do módulo collections
.
O construtor de namedtuple
recebe como parâmetro o nome da classe de tuplas nomeadas a ser criada e uma string com os nomes dos campos dessa classe, separados por espaços. O construtor devolve a nova classe criada (uma subclasse de namedtuple
) com os campos especificados. A nova classe então pode ser usada para criar as tuplas nomeadas.
Veja o exemplo abaixo que ilustra a criação e uso de uma classe de tuplas nomeadas chamada Aluno
:
from collections import namedtuple
Aluno = namedtuple("Aluno", "nusp nome idade curso")
aluno1 = Aluno(18632827, "John Lennon", 19, "Bacharelado em Ciência da Computação")
print("Primeiro aluno: ", aluno1)
print("Tipo: ", type(aluno1))
print()
aluno2 = Aluno(19817271, "Ringo Star", 21, "Licenciatura em Matemática")
print("Segundo aluno: ", aluno2)
print("Tipo: ", type(aluno2))
print()
# Exemplos de acesso a campos de uma tupla por meio de seus nomes
print("Nome do primeiro aluno: ", aluno1.nome)
print("Idade do primeiro aluno: ", aluno1.idade)
# Exemplos de acesso a campos de uma tupla por meio de suas posições
print("Nome do segundo aluno: ", aluno2[1])
print("Idade do segundo aluno: ", aluno2[2])
Para quem não conhece orientação a objetos ainda, a descrição da criação de tuplas nomeadas e o exemplo acima podem não ter ficado muito claros. Mas as próximas aulas (que serão sobre orientação a objetos em Python) ajudarão a esclarecê-los!
dict
)¶Já vimos alguns tipos de dados (str
, list
e tuple
) para lidar com coleções sequenciais, nas quais os elementos na coleção estão ordenados da esquerda para a direita e os seus valores são acessados por meio de índices que são números inteiros.
Agora veremos um outro tipo de dados do Python - o dict
(de dictionary, ou dicionário em português) - que também é usado para representar coleções. Entretanto, em um dict
a organização dos elementos não é sequencial.
Um dicionário é um tipo abstrato de dados que associa uma chave a um valor. A chave precisa ser única, ou seja, não pode haver chaves repetidas dentro do dicionário. A chave também deve ser imutável, ou seja, uma vez criada, ela permanece a mesma. Portanto, pode-se usar como chave strings, números e tuplas, mas não listas. Já o valor pode ser de qualquer tipo do Python.
Para criar um dicionário vazio chamado dic
, você pode fazer:
dic = {}
Observe que os elementos de um dicionário são delimitados por chaves ({}
), enquanto que os itens de uma lista são delimitados por colchetes ([]
).
Para criar um dicionário já com elementos dentro, basta colocar os elementos entre as chaves separados por vírgulas, e usando :
(dois pontos) para separar a chave do valor, como mostrado no exemplo abaixo:
disciplinas = {'MAC2166':'Introdução à Computação', 'MAT2453':'Cálculo Diferencial e Integral I'}
print("O conteúdo do meu dicionário de disciplinas é:\n", disciplinas)
Para ler, criar ou modificar um elemento do dicionário, temos que usar a chave do elemento entre colchetes, como nos exemplos abaixo:
estoque = {'banana':50, 'maçã':4, 'abacaxi':10} # cria um dicionário com 3 elementos
print("Dicionário inicial:", estoque)
estoque['melancia'] = 7 # adiciona no dicionário um novo elemento: o valor 7 associado à chave 'melancia'
print("Dicionário depois da adição de novo elemento:", dic)
estoque['banana'] += 15 # modifica o valor assocido à chave 'banana'
print("Dicionário depois da modificação do valor de um elemento:", estoque)
print("Valor associado à chave 'abacaxi' no dicionário:", estoque['abacaxi']) # lê o valor associado à 'abacaxi'
Quando tentamos obter o valor associado à uma chave que não existe no dicionário, uma exceção do tipo KeyError
é gerada (veja o exemplo abaixo):
estoque = {'banana':50, 'maçã':4, 'abacaxi':10}
print(estoque['pera'])
Podemos verificar se uma dada chave existe em um dicionário usando o operador in
, ou ainda verificar se uma chave não existe no dicionário usando not in
. Veja o exemplo abaixo:
estoque = {'banana':50, 'maçã':4, 'abacaxi':10}
if 'pera' in estoque: # verifica se a chave 'pera' existe no dicionário estoque
print("A quantidade de peras no estoque é:", estoque['pera'])
else:
print("Não vendemos peras!")
if 'abacate' not in estoque:
print("E também não vendemos abacates.")
Há diferentes formas de se percorrer todos os elementos de um dicionário usando um laço for
. Podemos usar o for
para iterar sobre as chaves contidas no dicionário e, a partir de cada chave, acessar o valor associado a ela no dicionário. Veja abaixo um exemplo disso:
estoque = {'banana': 50, 'laranja': 12, 'melancia': 7, 'kiwi': 23}
for chave in estoque:
valor = estoque[chave]
print("Temos %d unidades de %s no estoque."%(valor, chave))
Uma forma menos compacta para se iterar sobre as chaves de um dicionário (mas talvez mais legível para alguns) é usando o método keys()
de dict
, como mostrado abaixo:
for chave in estoque.keys():
valor = estoque[chave]
print("Temos %d unidades de %s no estoque."%(valor, chave))
É possível também iterar sobre os valores de um dicionário utilizando o método values()
de dict
. Assim, para saber quantas frutas há no estoque podemos escrever:
total = 0
for valor in estoque.values():
total += valor
print("Temos %d frutas no estoque."%(total))
Por fim, é possível iterar sobre os pares (chave,valor) de um dicionário usando o método items()
de dict
. Veja o exemplo abaixo:
for (fruta,quantidade) in estoque.items():
print("Temos %d unidades de %s no estoque."%(quantidade, fruta))
O conteúdo apresentado nesta aula é baseado no material disponível aqui e também aqui.
def main():
frase = input("Digite uma frase:\n")
freq_letras = {} # cria um dicionário vazio
for caractere in frase: # para cada caractere na frase, faça
if caractere not in ' .,;:?!\t\n': # se o caractere atual não é um caractere que deve ser ignorado
if caractere in freq_letras: # verifica se o caractere já está no dicionário
freq_letras[caractere] += 1 # Sim, então incrementa a sua frequência
else:
freq_letras[caractere] = 1 # Não, então inclui o caractere no dicionário,
# indicando 1 como frequência
for (letra,freq) in freq_letras.items():
print("A frequência da letra '%c' na frase é %d" %(letra, freq))
main()
Matrizes esparsas tipicamente possuem zero em quase todas as posições, e valores diferentes de zero em apenas algumas posições.
Uma matriz esparsa pode ser representada como um dicionário, utilizando as coordenadas como chave.
Por exemplo, a matriz esparsa abaixo
0 | 0 | 0 | 0 | 5 |
0 | 13 | 0 | -1 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 42 | 0 | 0 |
poderia ser representada pelo seguinte dicionário em Python:
mat_esparsa = {(0,4):5, (1,1):13, (1,3):-1, (3,3):42}
for (coordenada,valor) in mat_esparsa.items():
print("A posição", coordenada, "da matriz esparsa contém o valor ", valor)
Como exemplo, vamos implementar um jogo de batalha naval onde o mapa será representado como uma matriz esparsa mantida em um dicionário, com:
O “mar” onde estão as embarcações tem coordenadas de 0 a 99, tanto no eixo x quanto no eixo y.
A partir do esqueleto abaixo, escreva um programa que carrega um mapa em um dicionário usando a função dada carrega_mapa
e leia coordenadas do usuário até que ele desista ou até que não reste mais pontos para serem ganhos (ou seja, até que ele afunde todas as embarcações).
Para facilitar a detecção do fim do jogo, implemente uma função total_pontos
que retorna o total de pontos ainda disponível no dicionário.
Antes de terminar o programa, imprima quantos pontos o usuário ganhou.
def main():
# edite o código abaixo para resolver este exercício
mapa = carrega_mapa()
print(mapa)
def total_pontos( dic ):
''' (dict) -> int '''
# escreva a função
def carrega_mapa():
''' Retorna um dicionário contendo as coordenadas das
embarcações. O mapa poderia ser lido, por exemplo, de um
arquivo, ou as posições das embarcações poderiam ser
sorteadas.
Na implementação atual, o mapa está fixo.
'''
return {(2,5):100, # submarino
(20,60):30, (21,60):30, # cruzador
(42,71):20, (43,71):20, (44,71):20, (45,71):20} # porta-aviões
main()
Na estratégia de implementação mostrada abaixo, modifica-se o valor associado a uma posição definida no dicionário para zero toda vez que o usuário acertar uma embarcação.
def main():
mapa = carrega_mapa()
fim = False
pontos = 0
total = total_pontos(mapa)
print("Batalha Naval")
print("Você pode fazer até %d pontos\n"%total)
print("Digite as coordenadas separadas por vírgula")
while not fim:
x, y = input("Digite x, y (ou -1,-1 para terminar): ").split(',')
x, y = int(x), int(y)
print("Você jogou em: %d,%d" %(x,y))
if (x,y) == (-1,-1):
# Usuário pediu para encerrar o jogo
fim = True
elif (x,y) in mapa and mapa[x,y] > 0:
# (x,y) é a coordenada de um pedaço de embarcação ainda não atingido
valor = mapa[x,y]
print("Voce acertou uma embarcação e fez %d pontos" %valor)
pontos += valor
mapa[(x,y)] = 0 # troca o valor da posição para zero para indicar que foi atingida
if total_pontos(mapa) == 0:
# Usuário já ganhou todos os pontos possíveis
fim = True
else:
print("Água!!")
print("Você fez %d pontos" %pontos)
#----------------------------------------------------
def total_pontos(dic):
''' (dict) -> int '''
soma = 0
for coordenada in dic:
soma += dic[coordenada]
return soma
#----------------------------------------------------
def carrega_mapa():
''' Retorna um dicionário contendo as coordenadas das
embarcações. O mapa poderia ser lido, por exemplo, de um
arquivo, ou as posições das embarcações poderiam ser
sorteadas.
Na implementação atual, o mapa está fixo.
'''
return {(2,5):100, # submarino
(20,60):30, (21,60):30, # cruzador
(42,71):20, (43,71):20, (44,71):20, (45,71):20} # porta-aviões
#----------------------------------------------------
main()
Lambdas em Python são pequenas funções anônimas, definidas com uma sintaxe mais concisa (porém mais restritiva) que a de funções regulares. Uma função anônima é uma função sem nome.
O corpo de uma função lambda precisa ser uma única expressão. Portanto, funções lambda não podem fazer atribuições ou usar comandos como while
, return
, etc.
Formato geral de uma lambda:
lambda parâmetros : expressão
Exemplos:
# Cria uma lambda que recebe como parâmetros dois números
# e devolve a soma deles
# Armazena na variável funcSoma a referência para a lambda
funcSoma = lambda x,y: x + y
# Chama a lambda para calcular a soma de 5 e 10 e
# exibe o resultado
print(funcSoma(5,10))
# Na expressão da atribuição abaixo, uma função lambda é
# definida e imediamente chamada
valor = (lambda x: x + 1)(20)
print(valor)
Quando usadas da forma mostrada nos dois exemplos acima, as lambdas não parecem muito úteis. Aliás, esse tipo de uso não é mesmo recomendado.
Lambdas são mais úteis quando passadas como parâmetros para funções.
Veja abaixo um exemplo de uso de uma função lambda como parâmetro numa chamada à função sorted()
(que ordena sequências):
alunos = [("Paul", 21), ("Ringo", 18), ("John", 19)] # lista de tuplas de alunos
print("Alunos:", alunos)
alunos_ordenados = sorted(alunos)
print("Alunos ordenados:", alunos_ordenados)
alunos_ordenados_por_idade = sorted(alunos, key=lambda aluno: aluno[1])
print("Alunos ordenados por idade:", alunos_ordenados_por_idade)
No parâmetro opcional key
da função sorted()
, podemos passar uma função para personalizar a ordem de ordenação, como foi feito no exemplo acima.
Nesse exemplo, a lista de tuplas de alunos é ordenada de acordo com a idade (2° campo de uma tupla de aluno).
Ao parâmetro key
, foi atribuída uma função lambda que recebe uma tupla como parâmetro de entrada (aluno
) e devolve como saída o valor que está no posição 1 da tupla (aluno[1]
), que é a idade.
Assim, na ordenação dos itens em alunos
, a função sorted()
aplicará essa função lambda sobre cada item em alunos
para obter sua respectiva chave de ordenação.
Na primeira chamada à sorted()
no exemplo, nada foi passado ao parâmetro key
. Então, a função usou como chave de ordenação para cada tupla de aluno o primeiro elemento da tupla (que é o nome do aluno).
Veja abaixo a documentação da função `sorted():
help(sorted)
Abaixo, vemos um outro exemplo de uso de lambdas. No exemplo, definimos a função gera_multiplicador
que cria lambdas. A nova lambda é definida em função do parâmetro n
passado para gera_multiplicador
. A lambda criada é uma função que devolve o valor da multiplicação do seu parâmetro a
por n
.
def gera_multiplicador(n):
return lambda a : a * n
meu_duplicador = gera_multiplicador(2) # lambda a : a * 2
meu_triplicador = gera_multiplicador(3) # lambda a : a * 3
print(meu_duplicador(11)) #imprime o resultado da chamada (lambda a : a * 2)(11)
print(meu_triplicador(11)) #imprime o resultado da chamada (lambda a : a * 3)(11)
map()
, reduce()
e filter()
¶Funções lambda com frequência são usadas como parâmetros para as funções map()
, reduce()
e filter()
do Python.
map(função, sequência)
: devolve um iterador para uma sequência gerada a partir da aplicação da função em cada elemento no objeto iterável;filter(função, sequência)
: devolve um iterador para uma sequência com os elementos do iterável nos quais a aplicação da função devolve True
;reduce(função, sequência[, inicialização])
: aplica a função (que deve ter dois parâmetros) de forma acumulativa aos elementos de uma sequência, da esquerda para a direita, de modo a reduzir a sequência a um único valor. A reduce()
é uma função do módulo functools
.Exemplos:
lista = [1,2,3,4,5]
# Usa função map para gerar nova sequência
# com os quadrados dos números da lista original
lista_quadrados = map(lambda x: x*x, lista)
print(list(lista_quadrados))
lista = [1,2,3,4,5,6,7,8,9,10]
# Usa função filter para gerar nova sequência
# com os números pares da lista original
lista_pares = filter(lambda x: x % 2 == 0, lista)
print(list(lista_pares))
import functools
lista_pares = [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
# Usa a função reduce para agregar os elementos
# da lista de pares em um único valor, que neste exemplo
# é a soma do primeiro valor dos pares
# O acumulador começa com o valor zero.
soma = functools.reduce(lambda acumulador,par: acumulador + par[0], lista_pares, 0)
print("A soma é:", soma)
No exemplo acima, a reduce()
calcula a soma (((1+2)+3)+4), por meio da seguinte sequência de chamadas à função lambda:
chamada 1: acumulador = 0, par = (1, 'a'), resultado: 0+1 = 1
chamada 1: acumulador = 1, par = (2, 'b'), resultado: 1+2 = 3
chamada 1: acumulador = 3, par = (3, 'c'), resultado: 3+3 = 6
chamada 1: acumulador = 6, par = (4, 'd'), resultado: 6+4 = 10
Resultado final da reduce()
: 10
import functools
lista = [3,2,6,5,1,4]
# Usa a função reduce para agregar os elementos
# da lista em um único valor, que neste exemplo
# é o maior elemento da lista
maior = functools.reduce(lambda x,y: x if (x > y) else y, lista)
print("O maior valor na lista é:", maior)
No exemplo acima, a reduce()
realiza a seguinte sequência de chamadas à lambda, para obter o valor da redução:
chamada 1: x = 3, y = 2, resultado: 3 (3 > 2)
chamada 2: x = 3, y = 6, resultado: 6 (3 <= 6)
chamada 3: x = 6, y = 5, resultado: 6 (6 > 5)
chamada 4: x = 6, y = 1, resultado: 6 (6 > 1)
chamada 5: x = 6, y = 4, resultado: 6 (6 > 4)
Resultado final da reduce()
: 6
Mudando um pouco de assunto, agora vamos tratar da manipulação de arquivos.
Para abrir um arquivo para leitura, podemos usar a função open()
, passando como parâmetros para ela o nome (com caminho, se necessário) do arquivo a ser aberto e a string 'r'
(de read
, para indicar que o arquivo será aberto para leitura). A função devolve um objeto do tipo file
.
Para ler o conteúdo inteiro de um arquivo var_arquivo
já aberto para leitura, podemos chamar var_arquivo.read()
, que devolve uma string (str
).
Depois que o uso de um arquivo já tiver sido encerrado, é preciso fechar o arquivo por meio da função close()
.
Veja o exemplo a seguir, que abre um arquivo chamado 'meu_arquivo.txt', lê cada linha do arquivo e a imprime.
nome_do_arquivo = "meu_arquivo.txt"
arquivo = open(nome_do_arquivo, 'r') # abre o arquivo para leitura
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
conteudo = arquivo.read() # lê o conteúdo do arquivo
print(conteudo)
arquivo.close() # depois do uso, fecha o arquivo
Quando o arquivo é muito grande, ler o seu conteúdo inteiro de uma só vez não é uma boa ideia, pois ele pode ocupar toda a memória do computador. Nesse caso, o melhor é ler uma linha do arquivo por vez.
Para ler uma linha de um arquivo var_arquivo
já aberto para leitura, podemos chamar var_arquivo.readline()
, que também devolve uma string (str
). Quando se está no final do arquivo, a função readline()
devolve uma string vazia (''
).
nome_do_arquivo = "meu_arquivo.txt"
arquivo = open(nome_do_arquivo, 'r') # abre o arquivo para leitura
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
linha = arquivo.readline() # lê uma linha do arquivo
while linha != "": # enquanto não chegou ao final do arquivo
print(linha) # imprime a linha
linha = arquivo.readline() # lê uma nova linha do arquivo
arquivo.close() # depois do uso, fecha o arquivo
Obs.: No exemplo acima, é possível observar que linhas em branco que não existem no arquivo original foram impressas na saída. Quando lemos uma linha do arquivo com readline
, ela vem com o caracter de quebra ('\n'
) de linha no final. E o comando print
acima, depois imprimir a string toda em linha
, imprime uma quebra de linha (no seu comportamento padrão) - o que faz com que as quebras de linha apareçam dobradas na saída.
Para resolver o problema, podemos passar à função print
o parâmetro end=''
, como mostrado a seguir, para indicar ao print
que ele deve imprimir nada (string vazia ''
) depois de imprimir linha
. O valor default
do parâmetro end
é \n
.
nome_do_arquivo = "meu_arquivo.txt"
arquivo = open(nome_do_arquivo, 'r') # abre o arquivo para leitura
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
linha = arquivo.readline() # lê uma linha do arquivo
while linha != "": # enquanto não chegou ao final do arquivo
print(linha, end="") # imprime a linha
linha = arquivo.readline() # lê uma nova linha do arquivo
arquivo.close() # depois do uso, fecha o arquivo
Agora a impressão ficou correta.
Podemos também resolver o problema eliminado a quebra de linha do final de uma linha lida do arquivo. Essa solução envolve o uso do método rstrip()
, de strings.
nome_do_arquivo = "meu_arquivo.txt"
arquivo = open(nome_do_arquivo, 'r') # abre o arquivo para leitura
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
linha = arquivo.readline() # lê uma linha do arquivo
while linha != "": # enquanto não chegou ao final do arquivo
print(linha.rstrip()) # imprime a linha
linha = arquivo.readline() # lê uma nova linha do arquivo
arquivo.close() # depois do uso, fecha o arquivo
A chamada linha.rstrip()
que devolve uma cópia da string linha
sem os "caracteres brancos" que ela tiver em seu final. São considerados caracteres brancos os caracteres espaço (' '
), tabulação (\t
) e quebra de linha (\n
).
Temos também as funções lstrip()
(que devolve uma cópia da string eliminando todos os caracteres brancos do início da string) e strip()
(que devolve uma cópia da string eliminando todos os caracteres brancos do início e do fim da string). Veja os exemplos abaixo:
texto = "\n\n \t Pequeno texto de teste! \t\t \n\n"
print(texto)
print("--------------")
print(texto.rstrip())
print("--------------")
print(texto.lstrip())
print("--------------")
print(texto.strip())
print("--------------")
Para fazer um laço que lê todas as linhas de um arquivo (uma por vez), também podemos usar o comando for var_linha in arquivo:
, onde var_linha
é o nome da variável que armazenará o conteúdo de uma linha e var_arquivo
é o arquivo já aberto para leitura, como ilustrado abaixo:
nome_do_arquivo = "meu_arquivo_utf8.txt"
arquivo = open(nome_do_arquivo, 'r', encoding="utf8") # abre o arquivo para leitura
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
for linha in arquivo: # percorre cada linha do arquivo
print(linha, end="") # imprime a linha
arquivo.close() # depois do uso, fecha o arquivo
No exemplo acima, passamos um terceiro parâmetro para a função open()
, o parâmetro chamado encoding
. Esse parâmetro é opcional; quando não passamos nenhum valor para ele, o valor usado é a codificação padrão do Python 3, que é 'utf8'
. Um outro valor possível para o parâmetro encoding
é o 'latin1'
. O exemplo abaixo lê o arquivo 'meu_arquivo_latin1.txt', que tem codificação latin1
.
nome_do_arquivo = "meu_arquivo_latin1.txt"
arquivo = open(nome_do_arquivo, 'r', encoding="latin1") # abre o arquivo para leitura
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
for linha in arquivo: # percorre cada linha do arquivo
print(linha, end="") # imprime a linha
arquivo.close() # depois do uso, fecha o arquivo
É possível evitar de ter que fechar explicitamente um arquivo (com close()
) usando o comando with (...) as <nome_var> :
na sua abertura, como no exemplo abaixo. Ao final do corpo do with
, o comando with
fecha automaticamente o arquivo.
nome_do_arquivo = "meu_arquivo.txt"
with open(nome_do_arquivo, 'r') as arquivo: # abre o arquivo para leitura
# Corpo do WITH
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
for linha in arquivo: # percorre cada linha do arquivo
print(linha, end="") # imprime a linha
print("Fim!")
Importante: Para poder reler a partir da primeira linha um arquivo que está aberto e já foi lido, é preciso reabri-lo com a função open()
. Todo arquivo aberto tem um marcador que indica a posição do primeiro caracter que ainda não foi lido do arquivo (ou seja, a posição de início da próxima leitura a ser realizada). A função open()
põe o marcador no início do arquivo. A cada vez que chamamos a função read()
ou a função readline()
, o marcador se move para o caractere que vem em seguida do último caractere retornado. No caso de readline
, o marcador se move para o primeiro caractere da próxima linha. No caso de read
, o marcador se move para o final do arquivo.
Também podemos usar a função open()
para criar um arquivo de texto para a gravação de dados. Passamos como parâmetros para a função open
o nome (com caminho, se necessário) do arquivo a ser criado e a string 'w' (de write
, para indicar que o arquivo será aberto para escrita).
Para gravar uma string em um arquivo var_arquivo
já aberto para escrita, podemos usar a função var_arquivo.write()
.
Assim como na leitura de arquivos, depois que o uso de um arquivo aberto para escrita já tiver sido encerrado, é preciso fechar o arquivo por meio da função close()
.
Veja o exemplo a seguir, que cria um arquivo chamado 'meu_poema.txt'
e grava um poema nele.
nome_do_arquivo = "meu_poema.txt"
arquivo = open(nome_do_arquivo, 'w') # Cria ou abre o arquivo para escrita
poeminha = ["Batatinha quando nasce","Espalha a rama pelo chão","Menininha quando dorme"]
for linha in poeminha:
arquivo.write(linha) # grava uma linha do poema no arquivo
arquivo.write('\n') # coloca uma quebra de linha no final da linha do poema
arquivo.close() # depois do uso, fecha o arquivo
Quando abrimos um arquivo com a opção de escrita 'w'
, se o arquivo não existe previamente, ele será criado pela função open()
. Entretanto, caso o arquivo já exista, o seu conteúdo atual será sobreescrito (ou seja, perdido).
Para acrescentarmos conteúdo no final de um arquivo que já existe, podemos abrir o arquivo com a função open()
passando como parâmetros para ela o nome (com caminho, se necessário) do arquivo a ser aberto e a string 'a' (de append
, para indicar que o arquivo será aberto para escrita preservando o seu conteúdo atual). Caso o arquivo que se tenta abrir com opção 'a'
não exista previamente, ele será criado pela função open()
.
Para gravar uma string no final de um arquivo aberto com a opção 'a'
, também usamos a função write()
.
Veja o exemplo a seguir, que adiciona novas frases ao final do arquivo chamado 'meu_poema.txt'
:
nome_do_arquivo = "meu_poema.txt"
arquivo = open(nome_do_arquivo, 'a') # Abre o arquivo para append (acréscimo)
fim_poeminha = "Põe a mão no coração"
arquivo.write(fim_poeminha)
arquivo.close() # depois do uso, fecha o arquivo
Quando tentamos usar a função open()
para abrir para leitura um arquivo que não existe ou passamos um caminho inválido para um arquivo a ser aberto, a função gera o erro FileNotFoundError
, como mostrado abaixo:
nome_do_arquivo = "bla_bla.txt" # nome que não corresponde a um arquivo existente
arquivo = open(nome_do_arquivo, 'r')
O programa abaixo pede que o usuário digite o nome de um arquivo a ser aberto, mas caso o usuário digite um nome de arquivo que não existe, em vez da execução da função ser interrompida pelo erro FileNotFound
(gerado pela tentativa de abertura do arquivo), o programa pede para que o usuário digite novamente um nome de arquivo e tenta abri-lo novamente. O programa repete essas operações até que o usuário digite o nome de um arquivo que exista.
# Lê o nome do arquivo de dados e o abre para leitura
abriu = False
while not abriu:
nome_do_arquivo = input("Digite o nome do arquivo de dados: ")
try:
arquivo = open(nome_do_arquivo, 'r')
except FileNotFoundError:
print(nome_do_arquivo, " não encontrado. Você digitou o nome direito?")
else:
abriu = True
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
for linha in arquivo:
print(linha,end="")
arquivo.close() # depois do uso, fecha o arquivo
Para evitar que a execução do programa seja interrompida quando o erro FileNotFoundError
acontece, o programa usa o comando para tratamento de exceções try
.
O Python começa tentando executar o bloco de comandos associado à cláusula try
e caso tudo corra bem (no exemplo acima, se o arquivo existe e foi aberto para leitura com sucesso), então pula o bloco de comandos associado à cláusula except
e executa o bloco de comandos associado à cláusula else
. Mas se o erro FileNotFoundError
ocorrer durante a execução dos comandos no try
, então o bloco de comandos associado à cláusula except
é executado e depois o bloco de comandos do else
é pulado.
A cláusula else
é opcional. Portanto, podemos ter um comando try
só com except
. Além disso, no except
podemos não especificar o tipo de erro que se deseja capturar. Nesse caso, qualquer erro que for gerado durante a execução dos comandos no bloco do try
causará a execução dos comandos no bloco do except
.
Veja outro exemplo a seguir:
divisor = 0
try:
print("Agora eu vou dividir...")
divisao = 100 / divisor
print("Resultado da divisão:", divisao )
except:
print("Não consegui calcular a divisão!")
Escreva um programa que leia um arquivo onde cada linha contém o nome e as notas de um estudante e, para cada estudante, calcule e imprima a média das notas. Ao final, o programa deve imprimir também a média da turma.
Exemplo: para o arquivo notas.txt
com:
jose 10 15 20 30 40
pedro 23 16 19 22
suzana 8 22 17 14 32 17 24 21 2 9 11 17
gisela 12 28 21 45 26 10
joao 14 32 25 16 89
a saída deve ser:
Digite o nome do arquivo: notas.txt
Aluno: jose Média = 23.000000
Aluno: pedro Média = 20.000000
Aluno: suzana Média = 16.166667
Aluno: gisela Média = 23.666667
Aluno: joao Média = 35.200000
Média da turma = 23.606667
def main():
nome = input("Digite o nome do arquivo: ")
try:
arquivo = open(nome, 'r') # abre o arquivo para leitura
except:
print("Não consegui abrir o arquivo %s" %(nome))
else:
total = 0
cont_alunos = 0
for linha in arquivo:
dados = linha.split()
notas = dados[1:]
soma = 0
for n in notas:
soma += float(n)
media = soma/len(notas)
print("Aluno: %s \t Média = %f"%(dados[0],media))
total += media
cont_alunos += 1
print("Média da turma = %f"%(total/cont_alunos))
arquivo.close() # fecha o arquivo
main()
Obs.: Quando fazemos uma chamada do tipo S.split()
, ou seja, chamamos a split a partir de uma string S
sem passar para a função nenhum separador, a função separará S
nos caracteres brancos (espaços, tabulações e quebras de linhas); além disso, as strings vazias são removidas da lista de resultado. Veja os exemplos abaixo:
texto = "Para ser grande,\t sê inteiro:\tnada\nTeu exagera ou exclui."
print(texto)
print("----------")
print("Separando pelo caracter de espaço: ", texto.split(" "))
print("Separando pelo caracter de tabulação: ", texto.split("\t"))
print("Separando pelos caracteres brancos: ", texto.split())
Um módulo é um arquivo contendo definições e instruções Python. O nome do arquivo é o nome do módulo acrescido do sufixo .py
. Por exemplo, use seu editor de texto favorito para criar um arquivo chamado ponto.py
no diretório atual com o seguinte conteúdo:
import math
def distancia(Pa, Pb):
""" Calcula a distância entre dois pontos Pa = [xa,ya] e Pb = [xb,yb]"""
xa,ya = Pa #xa,ya = Pa[0],Pa[1]
xb,yb = Pb #xa,ya = Pb[0],Pb[1]
dx = xb-xa
dy = yb-ya
d = math.sqrt(dx*dx + dy*dy)
return d
Agora, crie um segundo arquivo chamado poligono.py
no mesmo diretório com o seguinte conteúdo:
# Arquivo poligono.py
import ponto
def perimetro(Pol):
"""Calcula o perímetro de um polígono Pol = [P1, P2, ..., Pn] composto por n pontos."""
peri = 0.0 # perímetro
Pant = Pol[-1] # ponto anterior
for Pi in Pol:
dist = ponto.distancia(Pant, Pi)
peri += dist
Pant = Pi
return peri
Considerando um polígono como uma lista dos seus vértices consecutivos, o módulo poligono acima define uma função para calcular o perímetro de um polígono fornecido, ou seja, a soma de todos os seus lados. Porém, como cada vértice é o ponto comum entre os lados do polígono, podemos calcular o tamanho de cada lado usando a função distancia do módulo ponto. Para isso, precisamos primeiramente importar o módulo ponto, usando o comando import ponto
. Feito isso, podemos então chamar a função distancia
usando a sintaxe ponto.distancia
.
No import
, o interpretador procura módulos em uma lista de diretórios incluídos na variável sys.path
.
É possível incluir diretórios na sys.path
usando append()
:
import sys
print(sys.path)
# Adiciona no sys.path o diretório que contém os
# módulos ponto.py e poligono.py
sys.path.append("/home/kellyrb/mac216-aula24")
print(sys.path)
Agora é possível importar o módulo polígono e usar a função perímetro:
import poligono
poligono.perimetro([[0,0],[1,0],[1,1],[0,1]])
4.0
Dentro de um módulo, o nome do módulo (como uma string) está disponível como o valor da variável global __name__
:
print(poligono.__name__)
No entanto, quando você roda um módulo Python no modo script (clicando em "Run Module" tal como indicado na figura abaixo), o código no módulo será executado, da mesma forma que quando é importado, mas com a variável name com valor "main", ao invés de valer a string do nome do módulo "poligono".
Isto significa que adicionando este código abaixo ao final do módulo poligono.py
, você pode tornar o arquivo utilizável tanto como script quanto como um módulo "importável", porque esse código no if
só roda se o módulo é executado como arquivo "principal" (como, por exemplo, executando o comando python3 poligono.py
num terminal). Se o módulo é importado, o código dentro do if
não será executado.
# Trecho a ser adicionado em poligono.py, para torná-lo utilizável
# tanto como script quanto como módulo
if __name__ == "__main__":
# só executa em modo script
per = perimetro([[0,0],[1,0],[1,1],[0,1]])
print("Perímetro:",per)
Sugestões de leitura para outros recursos importantes de Python não vistos em MAC0216: