collections.UserList é uma classe auxiliar para criar sequências mutáveis personalizadas. Ela armazena os elementos em uma lista comum disponível no atributo data e oferece uma base mais previsível para validação, normalização, logging e regras de domínio do que a herança direta de list.
O recurso é útil quando uma coleção precisa continuar se comportando como lista, mas deve controlar inserções, remoções, tipos aceitos ou operações em lote.
Primeiro exemplo
from collections import UserList
class ListaInteiros(UserList):
def _validar(self, valor):
if not isinstance(valor, int):
raise TypeError("apenas inteiros")
return valor
def append(self, valor):
super().append(self._validar(valor))
def insert(self, indice, valor):
super().insert(indice, self._validar(valor))
Validar somente append não basta. A lista também pode mudar por insert, atribuição por índice, slices, extend e +=.
Validando todas as mutações
class ListaInteiros(UserList):
def _validar(self, valor):
if not isinstance(valor, int):
raise TypeError("apenas inteiros")
return valor
def __setitem__(self, indice, valor):
if isinstance(indice, slice):
valor = [self._validar(item) for item in valor]
else:
valor = self._validar(valor)
super().__setitem__(indice, valor)
def append(self, valor):
super().append(self._validar(valor))
def insert(self, indice, valor):
super().insert(indice, self._validar(valor))
def extend(self, valores):
super().extend(self._validar(item) for item in valores)
Centralizar a regra em um método privado reduz inconsistências.
O atributo data
lista = ListaInteiros([1, 2, 3])
print(lista.data)
data contém a lista real. Modificá-la diretamente pode ignorar validações, portanto trate o atributo como detalhe de implementação.
Normalização de valores
class Tags(UserList):
def _normalizar(self, valor):
texto = str(valor).strip().casefold()
if not texto:
raise ValueError("tag vazia")
return texto
Decida se duplicatas são permitidas. Se a unicidade for a regra principal, um conjunto ou mapping pode representar melhor o domínio.
UserList versus list
Uma subclasse direta de list pode oferecer desempenho melhor e é necessária quando uma API exige exatamente esse tipo. UserList prioriza extensibilidade e encaminha operações para métodos Python mais fáceis de sobrescrever.
UserList versus MutableSequence
Implemente collections.abc.MutableSequence quando o armazenamento não for uma lista normal, como uma sequência em disco, janela virtual ou estrutura compacta. Use UserList quando uma lista interna for suficiente.
Operações que retornam novas listas
Teste soma, multiplicação, slicing e cópia. Dependendo do comportamento desejado, o resultado pode ser uma instância da classe personalizada ou uma lista comum. Defina isso como parte da API.
Ordenação
class Tarefas(UserList):
def sort(self, *, key=None, reverse=False):
registrar("ordenando tarefas")
super().sort(key=key, reverse=reverse)
Evite adicionar efeitos colaterais caros ou surpreendentes a métodos familiares.
Imutabilidade depois de congelar
class ListaCongelavel(UserList):
congelada = False
def _verificar(self):
if self.congelada:
raise TypeError("lista congelada")
def append(self, valor):
self._verificar()
super().append(valor)
Para imutabilidade permanente, uma tupla pode ser mais adequada.
Serialização
Algumas bibliotecas exigem uma lista concreta. Converta explicitamente:
import json
json.dumps(list(lista), ensure_ascii=False)
Erros comuns
- Validar apenas
append. - Esquecer atribuição por slice e
extend. - Modificar
datadiretamente. - Usar uma lista quando o domínio exige unicidade.
- Presumir o tipo retornado por soma, slicing ou cópia.
Boas práticas
Liste todas as operações mutáveis, centralize validação, use super(), teste os operadores e documente o tipo de retorno. Veja também os artigos internos sobre listas no Python e collections.
Conclusão
UserList é uma base útil para sequências personalizadas respaldadas por uma lista comum. Ela facilita invariantes consistentes sem depender dos detalhes internos de list.







