memoryview.count: conte valores sem copiar buffers

Publicado em: 06/10/2026
Tempo de leitura: 6 minutos
Código binário representando buffers e memória no Python

memoryview.count permite contar quantas vezes um valor aparece em uma visão de memória sem converter todo o buffer para bytes ou list. Isso é útil em processamento binário, protocolos, arquivos mapeados, imagens, áudio, redes e qualquer fluxo no qual copiar dados grandes aumenta o consumo de memória e o tempo de execução.

Neste guia, você vai entender como o método funciona, quais tipos de valores ele aceita, como o formato do buffer altera o resultado, quando usar count em vez de uma conversão, como lidar com fatias e estruturas multidimensionais e quais cuidados adotar ao processar dados externos.

O que é memoryview

Um memoryview expõe o protocolo de buffer do Python. Em vez de criar uma nova sequência com os mesmos dados, ele oferece uma janela sobre um objeto existente, como bytes, bytearray, array.array ou memória compartilhada. Alterações feitas em uma visão gravável podem atingir o objeto original, enquanto uma visão somente leitura permite inspeção eficiente.

dados = bytearray(b"ABRACADABRA")
visao = memoryview(dados)
print(visao[0])
print(len(visao))

Quando o formato é de bytes sem sinal, cada posição representa um inteiro entre 0 e 255. Por isso, contar a letra A significa contar o valor numérico retornado por ord("A").

Contagem básica

dados = memoryview(b"ABRACADABRA")
quantidade = dados.count(ord("A"))
print(quantidade)

O método percorre a visão e retorna a quantidade de elementos iguais ao valor informado. Ele não devolve posições e não altera o buffer. Para localizar a primeira ocorrência, use uma operação apropriada de busca; para reunir todas as posições, faça uma iteração controlada.

Por que evitar conversões

Uma solução comum é chamar bytes(visao).count(...). Ela funciona, mas materializa uma cópia quando a visão cobre outro objeto ou uma fatia complexa. Em buffers pequenos isso pode ser irrelevante. Em arquivos grandes, pacotes de rede ou lotes científicos, a cópia pode dobrar temporariamente o uso de memória.

def contar_zero(buffer):
    visao = memoryview(buffer)
    return visao.count(0)

A função recebe qualquer objeto compatível com o protocolo de buffer e conta bytes nulos sem impor uma representação intermediária.

Contando delimitadores em dados binários

Imagine um protocolo no qual mensagens são separadas por quebra de linha. Antes de dividir o conteúdo, você pode estimar quantos registros existem.

pacote = memoryview(b"um\ndois\ntres\n")
linhas = pacote.count(ord("\n"))
print(linhas)

Essa contagem não valida o protocolo inteiro. Ela apenas fornece uma métrica rápida para pré-alocação, diagnóstico ou checagem inicial.

Fatias sem copiar

Fatias de memoryview normalmente continuam referenciando a mesma memória. Assim, você pode contar valores em uma região específica.

dados = bytearray(range(100))
visao = memoryview(dados)
regiao = visao[20:60]
print(regiao.count(42))

Isso é útil para cabeçalhos, payloads e blocos fixos. Mesmo assim, valide os limites antes de criar a fatia, principalmente quando offsets vêm de arquivos ou da rede.

O formato importa

memoryview não representa apenas bytes. Uma visão pode ter formato de inteiro, ponto flutuante ou outro tipo suportado pelo exportador. O valor passado para count deve ser compatível com os elementos da visão.

from array import array

amostras = array("i", [10, 20, 10, 30, 10])
visao = memoryview(amostras)
print(visao.format)
print(visao.count(10))

Nesse caso, a unidade de comparação é um inteiro da matriz, não cada byte que compõe o inteiro. Isso torna o método útil para séries numéricas e buffers tipados.

Cast para outra interpretação

O método cast pode reinterpretar a mesma memória com outro formato quando as regras de tamanho e alinhamento permitem.

dados = bytearray([1, 0, 1, 0, 2, 0])
visao = memoryview(dados)
inteiros = visao.cast("H")
print(inteiros.count(1))

A interpretação depende da plataforma e do formato escolhido. Em dados persistidos ou transmitidos, trate explicitamente endianness e layout. Não presuma que um cast nativo produz o mesmo resultado em todos os ambientes.

Visões somente leitura e graváveis

count funciona como operação de leitura. Ele pode ser usado tanto em uma visão de bytes quanto em uma visão de bytearray. A diferença aparece quando outras partes do programa alteram o buffer durante o processamento.

Em código concorrente, memória compartilhada pode mudar entre duas leituras. Se você precisa de uma fotografia imutável, uma cópia deliberada pode ser necessária. Zero cópia é uma otimização, não uma garantia automática de consistência.

Buffers multidimensionais

Alguns exportadores expõem forma e dimensões. Antes de contar, verifique ndim, shape, strides e contiguous. Operações podem exigir uma visão compatível e contígua. Para dados científicos, confirme se a contagem percorre os elementos na representação esperada.

def descrever(visao):
    print("formato:", visao.format)
    print("dimensoes:", visao.ndim)
    print("shape:", visao.shape)
    print("contigua:", visao.contiguous)

Essa inspeção evita assumir que qualquer buffer é uma lista linear simples.

Exemplo com arquivo mapeado

Arquivos mapeados permitem acessar grandes arquivos como memória virtual. Uma visão pode contar marcadores sem carregar manualmente o arquivo inteiro em uma nova sequência.

import mmap

with open("dados.bin", "rb") as arquivo:
    with mmap.mmap(arquivo.fileno(), 0, access=mmap.ACCESS_READ) as mapa:
        visao = memoryview(mapa)
        try:
            print(visao.count(0))
        finally:
            visao.release()

Libere a visão antes de fechar o mapa. Caso contrário, o Python pode impedir o fechamento porque ainda existe um exportador ativo.

Liberação e ciclo de vida

Uma visão mantém uma referência ao objeto subjacente. Em recursos como mmap e memória compartilhada, use release ou um gerenciador de contexto para encerrar o acesso no momento correto.

with memoryview(bytearray(b"abcabc")) as visao:
    print(visao.count(ord("a")))

Depois da liberação, não tente reutilizar a visão.

Validação de entrada

Ao contar valores em dados externos, limite o tamanho aceito, valide offsets e confirme o formato. Uma contagem não substitui parser, autenticação ou verificação de integridade. Um arquivo malformado pode conter milhões de delimitadores e ainda assim violar completamente o formato esperado.

def contar_delimitador(buffer, valor, limite=10_000_000):
    visao = memoryview(buffer)
    if visao.nbytes > limite:
        raise ValueError("buffer acima do limite")
    if not 0 <= valor <= 255:
        raise ValueError("valor de byte inválido")
    return visao.cast("B").count(valor)

Desempenho e medição

Não presuma que zero cópia sempre é mais rápido em qualquer cenário. Meça com dados representativos, descarte aquecimento, repita a operação e observe memória além do tempo. Para uma única contagem em poucos bytes, a diferença será pequena. Para buffers grandes processados repetidamente, evitar conversões pode ser importante.

Erros comuns

Um erro frequente é passar uma string, como "A", para uma visão de bytes. O elemento esperado é um inteiro. Outro erro é confundir quantidade de bytes com quantidade de elementos em uma visão tipada. Também é comum manter uma visão ativa e tentar redimensionar o bytearray original, o que pode gerar exceção.

Boas práticas

Inspecione o formato antes de contar, use cast("B") apenas quando quiser interpretar a memória como bytes, libere visões ligadas a recursos externos, valide limites e documente se o valor representa byte, inteiro, amostra ou outra unidade. Prefira uma cópia explícita quando consistência for mais importante que economia de memória.

Conteúdos relacionados

Veja também os guias da Academify sobre bytes no Python, bytearray, arquivos binários e mmap. Consulte ainda a documentação oficial de memoryview e a documentação do protocolo de buffer.

Conclusão

memoryview.count é uma ferramenta direta para contar elementos em buffers sem criar representações intermediárias desnecessárias. Seu valor aparece principalmente quando o código precisa trabalhar com grandes blocos binários, fatias, memória mapeada ou sequências tipadas. Use o método junto com inspeção de formato, validação de limites e controle do ciclo de vida para obter desempenho sem perder previsibilidade.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Código Python com anotações de tipos
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evite imports circulares em anotações

    Aprenda annotationlib no Python para ler anotações adiadas, evitar imports circulares e criar ferramentas de introspecção seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python em tela representando inspeção de módulos e pacotes
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    inspect.ispackage: identifique pacotes Python

    Aprenda inspect.ispackage no Python para identificar pacotes, explorar módulos e criar ferramentas de introspecção seguras.

    Ler mais

    Tempo de leitura: 5 minutos
    05/10/2026
    Notebook exibindo código e gráficos de desempenho para análise do sys._jit no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sys._jit: detecte e meça o JIT experimental

    Aprenda sys._jit no Python para detectar suporte ao JIT experimental, medir desempenho e evitar decisões frágeis.

    Ler mais

    Tempo de leitura: 6 minutos
    05/10/2026
    Visualização de cálculos numéricos e precisão para math.fma no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    math.fma: cálculos com um único arredondamento

    Aprenda math.fma no Python para multiplicar e somar com um único arredondamento e melhorar cálculos numéricos.

    Ler mais

    Tempo de leitura: 6 minutos
    04/10/2026
    Desenvolvedores trabalhando em automação de unidades com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    os.listdrives: liste unidades do Windows no Python

    Aprenda a listar unidades disponíveis no Windows com os.listdrives e tratar caminhos de forma segura no Python.

    Ler mais

    Tempo de leitura: 5 minutos
    04/10/2026
    Código binário representando o protocolo Buffer no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    collections.abc.Buffer: tipagem para dados binários

    Aprenda collections.abc.Buffer no Python para tipar dados binários, usar memoryview e evitar cópias desnecessárias com segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    03/10/2026