Listas são a estrutura geral mais usada em Python, mas nem sempre são a melhor escolha para armazenar milhares ou milhões de números do mesmo tipo. O módulo array no Python, incluído na biblioteca padrão, oferece sequências mutáveis e compactas de valores numéricos. Cada elemento usa uma representação binária fixa definida por um código de tipo, o que reduz o consumo de memória e facilita a troca de dados com arquivos, buffers e APIs de baixo nível.
O módulo não substitui o NumPy em computação científica. Ele é mais simples, não oferece operações vetorizadas avançadas e trabalha em uma dimensão. Mesmo assim, é excelente quando você precisa evitar dependências externas, economizar memória, ler dados binários ou interagir com interfaces que aceitam o protocolo de buffer.
Este guia complementa nossos artigos sobre bisect, mmap, shelve, filecmp e fatiamento.
Quando usar array
Use array.array quando todos os elementos forem números compatíveis com o mesmo tipo C e você precisar de uma sequência mutável mais compacta que uma lista. Casos comuns incluem amostras de sensores, valores inteiros, dados de áudio, índices, coordenadas, contadores e blocos recebidos por rede.
Uma lista guarda referências para objetos Python. Um array guarda os valores diretamente em uma área contínua de memória. A economia depende do tipo escolhido e da implementação, por isso meça com dados reais.
Criar o primeiro array
from array import array
valores = array("i", [10, 20, 30, 40])
print(valores)
print(valores[0])O primeiro argumento é o código de tipo. O código i representa inteiros C com sinal. O tamanho exato pode depender da plataforma, portanto consulte itemsize quando o formato binário precisar ser previsível.
Códigos de tipo importantes
Entre os códigos mais usados estão b e B para inteiros de um byte, h e H para short, i e I para int, l e L para long, q e Q para inteiros de 64 bits quando disponíveis, além de f e d para ponto flutuante.
Não escolha um código apenas pelo nome. Verifique limites, sinal e itemsize. Inserir um valor fora da faixa gera OverflowError, o que é preferível a uma conversão silenciosa.
Adicionar e remover valores
dados = array("H")
dados.append(100)
dados.extend([200, 300, 400])
dados.insert(1, 150)
ultimo = dados.pop()
dados.remove(200)A API lembra a de listas. Métodos como append, extend, insert, pop, remove, reverse, count e index estão disponíveis. Todos os valores precisam ser compatíveis com o código de tipo.
Indexação e slicing
amostras = array("h", [2, 4, 6, 8, 10])
print(amostras[1:4])
amostras[1:3] = array("h", [40, 60])O slice devolve outro array com o mesmo código de tipo. Na atribuição, o valor também precisa ser um array compatível. Esse comportamento evita misturar representações binárias por acidente.
Memória e itemsize
valores = array("d", [1.5, 2.5, 3.5])
print(valores.itemsize)
print(len(valores) * valores.itemsize)O cálculo mostra os bytes usados pelos elementos, sem incluir o pequeno overhead do objeto. Compare com uma lista usando sys.getsizeof, lembrando que o tamanho da lista não inclui necessariamente todos os objetos referenciados.
Converter para lista
lista = valores.tolist()
novo = array("d")
novo.fromlist([4.5, 5.5])tolist() é útil para bibliotecas que esperam listas comuns. fromlist() adiciona valores de uma lista e valida todos os elementos. Se ocorrer erro de tipo, o array não deve ser tratado como parcialmente confiável sem verificação.
Trabalhar com bytes
numeros = array("I", [1, 2, 3])
bloco = numeros.tobytes()
copia = array("I")
copia.frombytes(bloco)tobytes() exporta a representação nativa. frombytes() exige que o comprimento seja múltiplo de itemsize. Dados vindos de fontes externas devem ser validados antes da leitura.
Endianness
A representação produzida por tobytes() usa a ordem de bytes nativa da máquina. Isso pode causar incompatibilidade entre sistemas little-endian e big-endian.
import sys
if sys.byteorder != "little":
numeros.byteswap()byteswap() inverte os bytes de cada item. Para protocolos permanentes, documente explicitamente a ordem de bytes e aplique a conversão de forma consistente. Não dependa do ambiente onde o arquivo foi criado.
Ler e escrever arquivos binários
dados = array("f", [0.5, 1.5, 2.5])
with open("amostras.bin", "wb") as arquivo:
dados.tofile(arquivo)
carregados = array("f")
with open("amostras.bin", "rb") as arquivo:
carregados.fromfile(arquivo, 3)fromfile() lê uma quantidade de itens, não de bytes. Se o arquivo terminar antes, gera EOFError, mas alguns itens podem já ter sido adicionados. Valide tamanho, trate a exceção e decida se deve descartar o resultado.
Protocolo de buffer
Arrays implementam o protocolo de buffer. Isso permite criar uma memoryview sem copiar os dados.
valores = array("i", [10, 20, 30])
visao = memoryview(valores)
print(visao.format, visao.itemsize)
visao[0] = 99A alteração afeta o array original. Enquanto uma view exportada estiver ativa, operações que redimensionam o array podem falhar. Libere a view quando terminar.
Interoperabilidade
Bibliotecas nativas, sockets, compressão, hashing e APIs de sistema frequentemente aceitam objetos que expõem buffers. Um array pode ser passado diretamente, evitando a criação de uma cópia intermediária em bytes.
Antes de compartilhar, confirme formato, alinhamento, sinal e ordem de bytes. O fato de duas APIs aceitarem buffers não significa que interpretem os elementos da mesma forma.
Limites numéricos
from array import array
a = array("B")
a.append(255)
# a.append(256) # OverflowErrorValide entradas antes de inserir. Para dados de usuários, converta explicitamente, rejeite valores fora da faixa e não use truncamento implícito. Para floats, considere NaN, infinito e diferenças de precisão.
Array versus list
Escolha lista quando os itens forem heterogêneos, quando você precisar armazenar objetos Python ou quando simplicidade for mais importante que memória. Escolha array para valores homogêneos, buffers compactos e interoperabilidade binária.
Operações como soma de todos os elementos ainda percorrem o array em Python e não ganham automaticamente a velocidade de uma biblioteca vetorizada.
Array versus NumPy
NumPy oferece arrays multidimensionais, broadcasting, álgebra linear, funções vetorizadas e muitos dtypes. O módulo array é menor, já vem com Python e atende tarefas básicas de armazenamento.
Para ciência de dados, imagens ou matrizes grandes, NumPy costuma ser a escolha correta. Para um utilitário leve ou formato binário simples, array pode ser suficiente.
Concorrência e mutabilidade
O array é mutável e não fornece sincronização de alto nível. Se várias threads ou processos modificarem os mesmos dados, use locks ou um protocolo adequado. Uma memoryview não transforma operações compostas em atômicas.
Erros frequentes
- Escolher um código de tipo sem verificar
itemsize. - Gravar bytes nativos em um formato que exige endianness fixo.
- Inserir valores fora da faixa.
- Confundir número de itens com número de bytes.
- Redimensionar o array enquanto existe uma memoryview ativa.
- Esperar operações vetorizadas como as do NumPy.
- Confiar em dados binários externos sem validar tamanho e formato.
Boas práticas
- Documente código de tipo, sinal e ordem de bytes.
- Valide limites antes da inserção.
- Use context managers ao trabalhar com arquivos.
- Cheque múltiplos de
itemsize. - Libere views antes de redimensionar.
- Faça benchmarks de memória e desempenho.
- Use NumPy quando precisar de cálculo vetorizado.
Conclusão
O módulo array no Python é uma solução prática para sequências numéricas compactas. Ele oferece uma API familiar, conversão para bytes, leitura e escrita de arquivos e integração eficiente com o protocolo de buffer.
Seu uso seguro depende de escolher o tipo correto, controlar limites e documentar a representação binária. Consulte a documentação oficial do módulo array e a documentação do protocolo de buffer para detalhes.







