Skip to content
This page has been auto-translated and may contain errors.View in English

Listas

Uma variável guarda uma coisa. Uma lista guarda várias coisas em ordem, todas sob um único nome. Um placar é uma sequência ordenada de pontuações. Um quiz é uma coleção de perguntas. Assim que você precisa gerenciar um grupo de valores relacionados, você precisa de uma lista.

Listas são a sequência ordenada e mutável de uso geral do Python. Elas se encaixam naturalmente em qualquer coisa que muda com o tempo: itens adicionados ou removidos, ordem embaralhada, conteúdo filtrado ou ordenado. Quando a ordem importa e a coleção muda, uma lista geralmente é a primeira escolha certa.

list é o array dinâmico do Python: uma sequência ordenada e mutável apoiada por uma alocação contígua no heap. O acesso aleatório é O(1). append() é O(1) amortizado porque o array aloca mais espaço do que necessário e cresce em caso de estouro. insert() e remove() são O(n) porque deslocam os elementos subsequentes. Esses custos devem orientar decisões sobre quando preferir outras estruturas.

Criando uma lista

Colchetes, valores separados por vírgulas. Listas podem conter qualquer mistura de tipos, e uma lista vazia é válida e comum como ponto de partida que você constrói ao longo do tempo.

Listas são definidas com a sintaxe de colchetes e preservam a ordem de inserção. Podem conter qualquer valor Python, inclusive outras listas. A lista vazia [] é o ponto de partida padrão quando você acumula itens incrementalmente.

O literal com colchetes aloca um novo objeto list no heap com alguma capacidade pré-alocada. Os elementos podem ser qualquer objeto Python; a lista armazena referências, não valores diretamente. Tipos de elementos heterogêneos são válidos, mas incomuns na prática fora de scripts rápidos.

python
scores   = [87, 92, 74, 65, 91]
players  = ["Ana", "Bruno", "Carlos"]
mixed    = ["Ana", 87, True, 3.14]   # qualquer tipo, embora incomum
empty    = []

Indexação e fatiamento

Listas usam a mesma numeração das strings: as posições começam em 0, números negativos contam a partir do final. Você lê qualquer item pela sua posição. Como listas são mutáveis, você também pode escrever em uma posição específica.

A indexação e o fatiamento de listas seguem as mesmas regras das strings. A diferença principal é a mutabilidade: você pode atribuir a um índice ou a uma fatia para alterar itens no lugar, algo que strings não permitem.

list.__getitem__ aceita inteiros e objetos slice, seguindo as mesmas regras de truncamento de str. __setitem__ permite a atribuição de itens. A atribuição de fatia substitui um intervalo de elementos e pode redimensionar a lista se a substituição tiver um tamanho diferente: lst[1:3] = [10, 20, 30] substitui dois itens por três.

python
scores = [87, 92, 74, 65, 91]

scores[0]      # 87  (primeiro)
scores[-1]     # 91  (último)
scores[1:3]    # [92, 74]
scores[:2]     # [87, 92]
scores[::-1]   # [91, 65, 74, 92, 87]  (invertido)

scores[0] = 90   # mutável: funciona (strings lançariam TypeError)

Adicionando itens

Três métodos para adicionar itens. append() adiciona um único item ao final e é o que você usará quase sempre. insert() adiciona em uma posição específica. extend() mescla outra lista.

append() é O(1) amortizado e é a forma padrão de construir uma lista item por item. insert() é O(n) porque desloca os elementos subsequentes. extend() é equivalente a += e mais eficiente do que repetidos append() dentro de um loop.

append() usa o buffer pré-alocado e só copia quando um estouro dispara um redimensionamento. O fator de crescimento é de cerca de 1,125x após os primeiros redimensionamentos, dando O(1) amortizado. insert(0, x) é O(n): cada elemento se desloca para a direita. Para inserções frequentes no início, collections.deque fornece appendleft em O(1). extend(iterable) chama __iter__ uma vez e cresce em uma única operação.

python
scores = [87, 92, 74]

scores.append(65)          # [87, 92, 74, 65]
scores.insert(1, 100)      # [87, 100, 92, 74, 65]
scores.extend([55, 71])    # [87, 100, 92, 74, 65, 55, 71]

Um erro comum: append() com uma lista adiciona a lista inteira como um único item, gerando uma lista dentro de uma lista. Use extend() para mesclar:

append(x) sempre adiciona x como um único elemento. Passar uma lista para append() gera uma lista aninhada. Use extend() quando quiser mesclar todos os itens de outra lista nesta:

append(x) chama list_append com x como um único objeto, independentemente do tipo. extend(iterable) chama __iter__ no argumento e adiciona cada elemento individualmente. O operador += chama __iadd__, que chama extend por baixo dos panos.

python
scores.append([55, 71])    # [..., [55, 71]]  lista aninhada, provavelmente errado
scores.extend([55, 71])    # [..., 55, 71]    mesclado, correto

Removendo itens

Quatro ferramentas para remover itens. remove() busca por valor. pop() remove por posição e te devolve o item. del remove por posição sem valor de retorno. clear() esvazia a lista inteira.

remove() é O(n): faz uma varredura pela primeira ocorrência por valor. pop() sem argumento é O(1) para o último item. pop(i) para qualquer outra posição é O(n) porque os elementos se deslocam. del scores[i] é equivalente a pop(i), mas descarta o valor de retorno.

remove(value) chama __eq__ em cada elemento até encontrar uma correspondência, depois desloca todos os elementos subsequentes para a esquerda: O(n). pop(-1) é O(1), sem necessidade de deslocamento. pop(i) para qualquer outro índice é O(n). Para remoções frequentes de posições arbitrárias, considere reestruturar seus dados ou usar uma coleção diferente.

python
scores = [87, 92, 74, 65, 91]

scores.remove(74)    # remove a primeira ocorrência de 74
scores.pop()         # remove e retorna o último item (91)
scores.pop(0)        # remove e retorna o item na posição 0 (87)
del scores[1]        # remove na posição 1, sem valor de retorno
scores.clear()       # remove tudo

remove() lança um ValueError se o valor não estiver na lista. Verifique com in primeiro se não tiver certeza:

python
if 74 in scores:
    scores.remove(74)

remove() lança ValueError em caso de falha. A verificação com in adiciona uma varredura extra de O(n); você faz duas passagens. Para código de uso único, isso é aceitável. O tratamento adequado de erros com try/except ValueError é abordado no capítulo Arquivos e exceções.

O padrão in + remove() faz duas varreduras de O(n). Quando a ordem não precisa ser preservada, uma abordagem mais rápida é trocar o alvo pelo último elemento e fazer pop: O(1). Para teste de pertencimento com lookup O(1), use set em vez de list, abordado no capítulo Tuplas, conjuntos.

Ordenação

sorted() retorna uma lista nova e ordenada e deixa a original intacta. .sort() ordena a lista no lugar e retorna None. Essa diferença importa mais do que parece.

sorted() é o padrão seguro: nunca modifica o original. .sort() modifica no lugar e retorna None, o que é uma armadilha comum. Atribuir o resultado de .sort() te dá None, não a lista ordenada. Use sorted() quando precisar do original intacto; use .sort() quando só quiser a versão ordenada.

Ambos usam Timsort: uma ordenação híbrida merge/insertion, O(n log n) no pior caso e O(n) em dados quase ordenados. Timsort é estável: elementos iguais preservam sua ordem relativa original. .sort() retorna None deliberadamente (separação comando-consulta). sorted() aceita qualquer iterável, não apenas listas, e sempre retorna uma lista.

python
scores = [87, 42, 96, 55, 71]

ranked = sorted(scores)            # [42, 55, 71, 87, 96] (nova lista)
scores.sort()                      # ordena no lugar, retorna None
scores.sort(reverse=True)          # [96, 87, 71, 55, 42]

result = scores.sort()             # result é None, não a lista ordenada

Operações úteis

O Python tem um conjunto de ferramentas embutidas que funcionam diretamente com listas. len(), sum(), min() e max() são as quatro que você usará constantemente.

As funções de sequência embutidas funcionam em qualquer lista. in é uma varredura linear para listas; se você precisa de testes de pertencimento rápidos e repetidos, converta para um conjunto. .index() lança ValueError se o valor não for encontrado.

len(), sum(), min(), max() todos chamam __iter__ e funcionam em qualquer iterável, não apenas listas. in é O(n) para listas; para lookup O(1), use set. .index(value) também é O(n). sum() tem start=0 como padrão e não suporta concatenação de strings; use "".join() para strings.

python
scores = [87, 92, 74, 65, 91]

len(scores)          # 5
sum(scores)          # 409
min(scores)          # 65
max(scores)          # 92
scores.count(87)     # 1
scores.index(74)     # 2
74 in scores         # True
74 not in scores     # False
scores.copy()        # cópia rasa
scores.reverse()     # inverte no lugar

Iterando

Um loop for percorre uma lista um item de cada vez. A variável após for recebe cada item por vez. Quando você também precisa da posição, enumerate() te dá ambos sem um contador manual.

for item in list invoca o iterador da lista e o avança a cada passo. enumerate(iterable, start=0) envolve o iterador e produz pares (index, value). Usar enumerate() é mais limpo e menos propenso a erros do que manter uma variável contadora.

for invoca iter(list) para obter um list_iterator, depois chama next() nele até StopIteration. enumerate() envolve qualquer iterador e produz pares (i, value). O parâmetro start desloca o contador, mas não afeta o índice subjacente. Desempacotar i, item = pair funciona porque enumerate produz tuplas.

python
players = ["Ana", "Bruno", "Carlos"]

for player in players:
    print(player)

for i, player in enumerate(players, start=1):
    print(f"{i}. {player}")
# 1. Ana
# 2. Bruno
# 3. Carlos

loops for e enumerate

for e enumerate() são abordados em detalhes no capítulo Controle de fluxo. Versão curta: for player in players executa uma vez por item; enumerate() te dá tanto a posição quanto o valor a cada iteração.

Listas aninhadas

Uma lista pode conter outras listas. É assim que você representa uma grade ou uma tabela: uma lista de linhas, cada linha sendo uma lista de valores. Dois conjuntos de colchetes acessam um item: o primeiro escolhe a linha, o segundo escolhe a coluna.

Listas aninhadas são listas de referências para listas. Cada lista interna é um objeto independente. Acesse com subscritos encadeados: grid[row][col]. Modificar uma lista interna afeta a lista externa porque a lista externa mantém uma referência ao mesmo objeto.

Listas aninhadas não são um verdadeiro array 2D: a lista externa mantém referências de objetos, e as listas internas podem ter tamanhos e tipos diferentes. O acesso encadeia duas chamadas __getitem__. A cópia rasa de uma lista aninhada copia o container externo, mas não as listas internas; modificações nas listas internas afetam ambas as cópias.

python
grid = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]

grid[0]       # [1, 2, 3]
grid[1][2]    # 6  (linha 1, coluna 2)

Mutabilidade: a armadilha

Isso surpreende quase todo mundo. Atribuir uma lista a uma nova variável não faz uma cópia. Os dois nomes apontam para a mesma lista. Mude um e você muda o outro. Para obter uma cópia independente, você precisa pedir explicitamente.

A atribuição de lista copia a referência, não o objeto. Os dois nomes apontam para a mesma lista subjacente. Mutações por qualquer um dos nomes afetam os mesmos dados. Quando você precisa de dados independentes, copie explicitamente com .copy(), list(), ou uma fatia completa [:].

b = a vincula um segundo nome ao mesmo objeto lista. Qualquer mutação através de b modifica o objeto para o qual a também está apontando. .copy() e a[:] criam uma cópia rasa: um novo objeto lista com as mesmas referências de elementos. Para listas planas de valores imutáveis, isso é seguro; para listas aninhadas, os objetos internos ainda são compartilhados.

python
a = [1, 2, 3]
b = a            # b não é uma cópia; aponta para a mesma lista

b.append(4)
print(a)         # [1, 2, 3, 4]  (mudou: a e b são a mesma lista)
python
b = a.copy()    # cópia independente
b = list(a)     # mesmo resultado
b = a[:]        # também a mesma coisa

# Listas aninhadas ainda compartilham seus objetos internos:
matrix = [[1, 2], [3, 4]]
copy   = matrix.copy()

copy[0].append(99)
print(matrix)   # [[1, 2, 99], [3, 4]]  (a lista interna foi compartilhada)

Para estruturas aninhadas onde você precisa de total independência, copie cada lista interna manualmente, ou use copy.deepcopy() da biblioteca padrão, abordado no capítulo Módulos.

Mais métodos

MétodoO que faz
.append(item)Adiciona ao final
.insert(i, item)Insere na posição i
.extend(iterable)Adiciona todos os itens de um iterável
.remove(value)Remove a primeira ocorrência do valor
.pop(i)Remove e retorna o item na posição i (padrão: último)
.clear()Remove todos os itens
.index(value)Posição da primeira ocorrência
.count(value)Número de ocorrências
.sort()Ordena no lugar
.reverse()Inverte no lugar
.copy()Retorna uma cópia rasa

Na prática

Construindo um rastreador de pontuações: adicionar resultados, ordená-los e imprimir um resumo.

python
scores = []

scores.append(87)
scores.append(54)
scores.append(92)
scores.append(67)
scores.append(45)

scores.sort(reverse=True)

print(f"Pontuações ordenadas: {scores}")
print(f"Maior: {scores[0]}")
print(f"Menor: {scores[-1]}")
print(f"Média: {sum(scores) / len(scores):.1f}")
print(f"Top 3: {scores[:3]}")

Duas listas paralelas de nomes e pontuações: encontrar o melhor desempenho e imprimir os resultados ordenados.

python
names  = ["Ana", "Bruno", "Carla", "Daniel"]
scores = [87, 74, 92, 55]

best_score  = max(scores)
best_index  = scores.index(best_score)
best_player = names[best_index]

print(f"Melhor jogador: {best_player} ({best_score})")
print(f"Média:          {sum(scores) / len(scores):.1f}")

ranked = sorted(scores, reverse=True)
print(f"Distribuição (ordenada): {ranked}")

for i in range(len(ranked)):
    print(f"  Posição {i + 1}: {ranked[i]}")

Demonstrando a diferença entre aliasing e cópia, e entre cópias rasas e profundas de listas aninhadas.

python
# Aliasing: b não é uma cópia
a = [1, 2, 3]
b = a
b.append(4)
print(a)    # [1, 2, 3, 4]  (mesmo objeto)

# Cópia rasa: a lista externa é independente, as listas internas são compartilhadas
matrix    = [[1, 2, 3], [4, 5, 6]]
shallow   = matrix.copy()
shallow[0].append(99)
print(matrix)    # [[1, 2, 3, 99], [4, 5, 6]]  (lista interna compartilhada)

# Cópia profunda manual com um loop for (sem necessidade de imports)
matrix    = [[1, 2, 3], [4, 5, 6]]
deep_copy = []
for row in matrix:
    deep_copy.append(row[:])    # copia cada lista interna explicitamente

deep_copy[0].append(99)
print(matrix)    # [[1, 2, 3], [4, 5, 6]]  (inalterado)