Listas, tuplos e strings
Indexação, slices, mutabilidade, aliasing, métodos e transformações de texto.
Uma sequência guarda elementos por ordem. Um índice escolhe um elemento; um slice escolhe uma parte da sequência. Listas, tuplos e strings partilham estas operações, mas diferem no que podes alterar.
Índices e slices
Com valores = [10, 20, 30, 40, 50], os índices positivos são 0 a 4. valores[-1] é 50 e valores[-5] é 10.
valores[inicio:fim:passo] seleciona do início, incluído, ao fim, excluído. valores[1:4] dá [20, 30, 40]. valores[::2] dá [10, 30, 50]. valores[::-1] inverte a ordem. Um índice fora dos limites dá erro; um slice pode cortar nos limites e devolver uma sequência vazia.
| Operação | Resultado para valores |
|---|---|
len(valores) | 5 |
valores[:2] | [10, 20] |
valores[2:] | [30, 40, 50] |
valores[-3:-1] | [30, 40] |
30 in valores | True |
Alterar uma lista
append(x) acrescenta um elemento. extend(iteravel) acrescenta cada elemento do iterável. Com uma lista [1], append([2, 3]) cria [1, [2, 3]]; extend([2, 3]) cria [1, 2, 3].
insert(i, x) insere antes da posição i. remove(x) retira a primeira ocorrência de um valor e falha se não o encontrar. pop(i) retira e devolve o elemento naquela posição. Sem argumento, pop usa a última posição.
lista.sort() altera a própria lista e devolve None. sorted(lista) devolve outra lista ordenada. Não escrevas lista = lista.sort(), porque perderias a associação à lista.
index(x) devolve a posição da primeira ocorrência e falha se o valor não existir. count(x) conta ocorrências e pode devolver zero. reverse() inverte a lista atual; clear() remove todos os seus elementos. Estes métodos de alteração devolvem None, exceto operações como pop, que devolvem o elemento retirado.
del lista[i] remove por posição e del lista[inicio:fim] remove um slice. del lista[:] esvazia o objeto, conservando os nomes que o referem; del lista apaga a associação desse nome, não necessariamente o objeto. list(iteravel) constrói outra lista a partir dos seus elementos.
Dois nomes para a mesma lista
Atribuir uma lista a outro nome não cria uma cópia:
original = [2, 4, 6]
alias = original
copia = original.copy()
alias[0] = 99
copia.append(8)
print(original)
print(copia)Dados de entrada
A saída é [99, 4, 6] e [2, 4, 6, 8]. alias e original apontam para a mesma lista. copia aponta para outra lista.
Esta cópia é superficial: numa lista de listas, copia a lista exterior, mas continua a partilhar as listas interiores. [[0] * 3] * 2 repete referências à mesma linha. Para linhas independentes, usa [[0] * 3 for _ in range(2)].
Vetores e matrizes com listas
Uma lista de números pode representar um vetor. Para vetores de igual comprimento, o produto escalar soma produtos das posições correspondentes. Em [2, 3, 4] e [1, 0, -2], calculamos 2 × 1 + 3 × 0 + 4 × (−2) = −6.
a = [2, 3, 4]
b = [1, 0, -2]
if len(a) != len(b):
raise ValueError("Vetores com dimensões diferentes")
produto = 0
for i in range(len(a)):
produto += a[i] * b[i]
print(produto)Dados de entrada
O acumulador começa em zero. Após cada posição, vale 2, 2 e −6. zip(a, b) também pode emparelhar valores, mas termina quando a sequência mais curta termina; verifica os comprimentos antes de o usar para este cálculo.
Uma lista de listas representa uma matriz. m[i][j] acede à coluna j da linha i. len(m) conta linhas; len(m[i]) conta elementos dessa linha. Uma matriz retangular tem todas as linhas do mesmo comprimento.
a = [[2, 1], [0, 3]]
b = [[4, 0], [5, -1]]
if len(a) != len(b) or any(len(x) != len(y) for x, y in zip(a, b)):
raise ValueError("Matrizes com dimensões diferentes")
soma = []
for i in range(len(a)):
linha = []
for j in range(len(a[i])):
linha.append(a[i][j] + b[i][j])
soma.append(linha)
print(soma)Dados de entrada
O resultado é [[6, 1], [5, 2]]. O ciclo externo escolhe a linha e o interno percorre as colunas. Criamos uma lista nova em cada linha. [[0] * 2] * 2 repetiria referências à mesma lista: alterar uma linha poderia alterar a outra. Usa [[0] * 2 for _ in range(2)] para criar duas linhas independentes.
Uma soma de listas, a + b, concatena as linhas; não soma as células. A parte de NumPy apresenta operações vetorizadas, com arrays e eixos explícitos.
Tuplos e desempacotamento
Um tuplo é uma sequência que não permite substituir os seus elementos. ponto = (2, 5) pode representar duas coordenadas. x, y = ponto associa a primeira a x e a segunda a y. O número de nomes deve corresponder ao número de valores, a menos que uses captura com *.
Um tuplo de um elemento precisa de vírgula: (3,). (3) é apenas o inteiro 3 entre parênteses. Um tuplo pode conter uma lista; não podes substituir essa lista dentro do tuplo, mas a lista continua a ser mutável.
Transformar texto
Uma string é imutável. nome[0] = "A" falha. Métodos como strip, lower e replace devolvem novas strings, pelo que precisas de guardar o resultado se quiseres usá-lo depois.
linha = " Porto;3;2.50 "
campos = linha.strip().split(";")
cidade = campos[0].lower()
quantidade = int(campos[1])
preco = float(campos[2])
print(cidade, quantidade * preco)
print(" | ".join(campos))Dados de entrada
A primeira linha é porto 7.5. A segunda é Porto | 3 | 2.50. strip retira espaços nos extremos, split divide pelo separador e join junta strings com um separador entre elas. strip("ab") retira caracteres a e b dos extremos; não retira uma substring exata.
find devolve o índice da primeira ocorrência, ou -1 se não existir. count conta ocorrências não sobrepostas. startswith e endswith testam extremos. Ao ordenar strings, Python compara códigos dos caracteres, não regras linguísticas de ordenação.
Construir uma nova lista
quadrados = [n * n for n in range(1, 4)]
positivos = [n for n in [-1, 2, 0, 3] if n > 0]
Uma compreensão calcula um elemento por valor percorrido. A condição opcional seleciona os valores antes de os transformar. Os resultados são [1, 4, 9] e [2, 3]. Se a expressão tiver muitos ramos, usa um ciclo normal para tornar os passos legíveis.
Ver as operações em ação
Exercícios
Selecionar posições
Com x = [10, 20, 30, 40, 50, 60], qual é a soma de x[1:5
]?Primeira pista
Começa no índice 1 e avança de dois em dois sem incluir o índice 5.
Mais uma pista
Ver solução
Erros frequentes
Somar os valores dos índices 1, 3 e 5, incluindo o limite final.
Prever uma alteração partilhada
a = [1, 2]; b = a; c = a.copy(); b[0] = 9. Quanto vale c[0]?
Primeira pista
Mais uma pista
c foi criada antes da alteração e tem os seus próprios elementos exteriores.
Ver solução
c[0] continua a ser 1. a[0] e b[0] passam ambos a 9.
Erros frequentes
Tratar toda a atribuição como uma cópia ou concluir que a cópia superficial partilha estes inteiros substituídos.
Criar linhas independentes
Explica por que [[0] * 3] * 2 não permite alterar uma célula de uma linha sem afetar a outra. Escreve uma construção correta.
Primeira pista
Mais uma pista
É preciso criar a linha dentro de cada iteração, em vez de a repetir depois.
Ver solução
A primeira expressão cria uma linha e refere-a duas vezes. A compreensão executa [0] * 3 em cada iteração e cria duas linhas independentes.
Confere a tua resposta:
- Identifiquei que as duas posições exteriores referem a mesma lista interior.
- Usei [[0] * 3 for _ in range(2)].
- Conferi que alterar matriz[0][0] não muda matriz[1][0].
Erros frequentes
Dizer apenas que Python não suporta matrizes ou fazer uma cópia superficial da lista exterior.
Reconhecer linhas partilhadas
m = [[0, 0]] * 2; m[0][1] = 7. Quanto vale m[1][1]?
Primeira pista
Mais uma pista
Ver solução
O valor é 7. A alteração afeta o único objeto de linha. Para linhas independentes, usa [[0, 0] for _ in range(2)].
Erros frequentes
Confundir repetir uma referência com criar uma cópia de cada linha.