functools.partial no Python: guia prático

Publicado em: 06/08/2026
Tempo de leitura: 6 minutos

O functools.partial no Python permite criar novas funções a partir de funções existentes, fixando antecipadamente alguns argumentos. O recurso é simples, mas extremamente útil quando você precisa adaptar callbacks, reduzir repetição, preparar funções para APIs que exigem uma assinatura específica ou deixar pipelines mais legíveis.

Neste guia, você vai entender como partial() funciona, quando ele melhora o código, quais armadilhas evitar e como combiná-lo com funções nomeadas, métodos, decorators, callbacks e testes. O conteúdo complementa nossos artigos sobre funções em Python, funções lambda, decorators, args e kwargs e type hints.

O que é functools.partial

partial() recebe uma função e alguns argumentos. O resultado é um novo objeto chamável que reutiliza a função original com esses valores já preenchidos.

from functools import partial

def potencia(base, expoente):
    return base ** expoente

quadrado = partial(potencia, expoente=2)

print(quadrado(5))  # 25

A função original continua intacta. O objeto quadrado apenas guarda que o argumento expoente deve valer 2. Quando você chama quadrado(5), internamente o Python executa potencia(5, expoente=2).

Por que usar partial em vez de repetir argumentos

Imagine uma aplicação que converte vários valores para reais usando sempre a mesma taxa:

def converter(valor, taxa, arredondar=True):
    resultado = valor * taxa
    return round(resultado, 2) if arredondar else resultado

converter_para_real = partial(converter, taxa=5.42)

print(converter_para_real(10))
print(converter_para_real(25))

Sem partial, você repetiria taxa=5.42 em toda chamada ou criaria uma função wrapper manual. A versão parcial deixa claro que existe uma operação especializada.

Argumentos posicionais

Os argumentos posicionais fornecidos ao criar o partial são inseridos antes dos argumentos enviados posteriormente.

def juntar(prefixo, texto, sufixo):
    return f"{prefixo}{texto}{sufixo}"

com_colchetes = partial(juntar, "[")
print(com_colchetes("Python", "]"))

O resultado será [Python]. Esse comportamento exige atenção à ordem da assinatura original.

Argumentos nomeados

Argumentos nomeados são frequentemente mais legíveis:

import json
from functools import partial

json_legivel = partial(
    json.dumps,
    ensure_ascii=False,
    indent=2,
    sort_keys=True,
)

print(json_legivel({"curso": "Python", "ativo": True}))

Esse padrão cria um serializador configurado uma única vez. A documentação oficial de functools.partial detalha como os argumentos são armazenados e combinados.

Sobrescrever argumentos

Argumentos nomeados definidos no partial podem ser substituídos em uma chamada posterior:

json_compacto = partial(json.dumps, ensure_ascii=False, indent=2)

print(json_compacto({"a": 1}, indent=None))

O valor mais recente de indent prevalece. Use essa flexibilidade quando fizer sentido, mas evite criar objetos parciais cuja configuração seja constantemente anulada.

Callbacks com assinatura compatível

Muitas bibliotecas chamam callbacks com uma assinatura fixa. partial ajuda a anexar contexto sem usar variáveis globais.

def registrar_evento(categoria, mensagem):
    print(f"[{categoria}] {mensagem}")

registrar_erro = partial(registrar_evento, "ERRO")
registrar_info = partial(registrar_evento, "INFO")

registrar_erro("Arquivo não encontrado")
registrar_info("Processamento concluído")

Em interfaces gráficas, filas, schedulers e frameworks web, esse padrão torna callbacks pequenos e previsíveis.

Uso com map

partial pode preparar uma função para map():

def aplicar_desconto(valor, percentual):
    return valor * (1 - percentual)

com_desconto = partial(aplicar_desconto, percentual=0.10)
precos = [100, 250, 80]

resultado = list(map(com_desconto, precos))
print(resultado)

O resultado é uma lista com desconto de 10% aplicado a cada valor.

Uso com sorted e key

Uma função parcial também pode ser usada como chave de ordenação:

def distancia(alvo, valor):
    return abs(valor - alvo)

mais_perto_de_10 = partial(distancia, 10)
valores = [1, 20, 8, 13, 5]

print(sorted(valores, key=mais_perto_de_10))

O código deixa explícito que a ordenação considera a distância até 10.

partial versus lambda

Uma lambda poderia resolver muitos dos mesmos casos:

quadrado_lambda = lambda base: potencia(base, expoente=2)
quadrado_partial = partial(potencia, expoente=2)

partial tende a ser melhor quando a intenção é apenas fixar argumentos. Lambda é mais adequada quando existe transformação adicional, condição ou composição de expressões.

Vantagens sobre wrappers manuais

Um wrapper manual permite documentação e lógica adicional:

def quadrado(base):
    """Retorna o quadrado de um número."""
    return potencia(base, 2)

Esse formato é preferível quando a função especializada faz parte da API pública, precisa de docstring própria ou contém validação. Use partial para adaptações diretas e locais.

Inspecionar o objeto partial

Objetos parciais expõem atributos úteis:

quadrado.func
quadrado.args
quadrado.keywords
  • func: função original;
  • args: argumentos posicionais fixados;
  • keywords: argumentos nomeados fixados.

Esses atributos ajudam em testes, depuração e ferramentas de introspecção.

Nome e documentação

Um objeto partial não recebe automaticamente o mesmo __name__ e a mesma docstring da função original. Para APIs públicas, você pode usar functools.update_wrapper().

from functools import partial, update_wrapper

quadrado = partial(potencia, expoente=2)
update_wrapper(quadrado, potencia)

Mesmo assim, o nome herdado continuará representando a função original, não necessariamente a especialização. Em código público, um wrapper nomeado pode comunicar melhor a intenção.

partialmethod em classes

Dentro de classes, existe functools.partialmethod, criado para funcionar corretamente com o protocolo de descriptors.

from functools import partialmethod

class Publicador:
    def enviar(self, mensagem, nivel):
        print(nivel, mensagem)

    informar = partialmethod(enviar, nivel="INFO")
    alertar = partialmethod(enviar, nivel="ALERTA")

p = Publicador()
p.informar("Servidor iniciado")

A documentação oficial de partialmethod explica o comportamento com métodos e descriptors.

Objetos mutáveis

Os argumentos são guardados por referência. Se você fixar uma lista ou dicionário e depois modificá-lo, as chamadas futuras verão o conteúdo atualizado.

config = {"modo": "teste"}

def executar(nome, config):
    return nome, config

executar_configurado = partial(executar, config=config)
config["modo"] = "produção"

print(executar_configurado("backup"))

Esse comportamento pode ser intencional, mas frequentemente gera surpresas. Prefira objetos imutáveis ou copie a configuração no momento adequado.

Assinaturas e ferramentas

inspect.signature() normalmente consegue mostrar uma assinatura adaptada para objetos partial, o que melhora integração com IDEs e validação.

from inspect import signature
print(signature(quadrado))

Ainda assim, frameworks que dependem de metadados específicos podem exigir wrappers explícitos.

Type hints

Ferramentas de tipagem podem inferir parte do comportamento, mas especializações complexas nem sempre ficam claras. Quando a função parcial é importante, atribua uma anotação:

from collections.abc import Callable

quadrado_tipado: Callable[[float], float] = partial(
    potencia,
    expoente=2,
)

Isso melhora autocomplete e análise estática.

Testar funções parciais

Teste o comportamento, não apenas a existência do objeto:

def test_quadrado():
    assert quadrado(4) == 16
    assert quadrado(-3) == 9

Quando os argumentos fixados fazem parte da regra, você também pode verificar args e keywords.

Serialização

Objetos parciais podem ser serializados em alguns contextos quando a função e os argumentos também são serializáveis. Não dependa disso para executar dados não confiáveis. Formatos baseados em pickle podem executar código durante a desserialização.

Desempenho

O custo adicional de um partial costuma ser pequeno e raramente deve orientar a decisão. Priorize clareza e meça com timeit quando estiver em um trecho realmente crítico.

Erros frequentes

  • Fixar argumentos na ordem errada.
  • Usar partial quando um wrapper documentado seria mais claro.
  • Armazenar listas e dicionários mutáveis sem perceber.
  • Esquecer que keywords podem ser sobrescritas.
  • Usar partialmethod de forma intercambiável com partial em classes.
  • Presumir que nome e docstring serão preservados.
  • Criar especializações demais e dificultar a leitura.

Boas práticas

  • Use nomes que revelem a especialização.
  • Prefira keywords para configurações importantes.
  • Mantenha o objeto parcial próximo de onde é usado.
  • Evite argumentos mutáveis compartilhados.
  • Use wrappers para APIs públicas e validações.
  • Documente callbacks que carregam contexto.
  • Teste a assinatura esperada pela biblioteca consumidora.

Conclusão

O functools.partial no Python é uma ferramenta prática para especializar funções sem duplicar lógica. Ele reduz repetição, facilita callbacks, adapta assinaturas e deixa configurações recorrentes explícitas.

Use partial quando a transformação consiste principalmente em fixar argumentos. Quando você precisar de documentação própria, validação, tratamento de erros ou lógica adicional, uma função wrapper tradicional será mais clara. Com essa distinção, o recurso melhora a legibilidade sem esconder o fluxo do programa.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Documento e caixa de entrada representando caixas de e-mail com mailbox no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    mailbox no Python: caixas de e-mail

    Aprenda mailbox no Python para ler, criar e migrar caixas Maildir, mbox e MH com locking, mensagens, flags e tratamento

    Ler mais

    Tempo de leitura: 6 minutos
    12/08/2026
    Editor de texto representando formatação com textwrap no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    textwrap no Python: formate textos

    Aprenda textwrap no Python para quebrar, preencher, encurtar, indentar e remover recuos de textos com controle de largura e espaços.

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Pasta e lupa representando filtros de nomes com fnmatch no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    fnmatch no Python: filtre nomes de arquivos

    Aprenda fnmatch no Python para filtrar nomes de arquivos com curingas, controlar maiúsculas, excluir padrões e evitar confundir glob com

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Monitor com dados binários representando arrays numéricos compactos no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    array no Python: números compactos

    Aprenda array no Python para armazenar números compactos, manipular bytes, arquivos binários e buffers com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    10/08/2026
    Círculo cromático representando conversões RGB, HSV e HLS com colorsys no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    colorsys no Python: RGB, HSV e HLS

    Aprenda colorsys no Python para converter cores entre RGB, HSV, HLS e YIQ, gerar paletas e evitar erros com escalas

    Ler mais

    Tempo de leitura: 6 minutos
    09/08/2026
    Ícone de configuração representando arquivos plist com plistlib no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    plistlib no Python: arquivos plist

    Aprenda plistlib no Python para ler e gravar arquivos plist XML e binários, validar dados e integrar configurações Apple com

    Ler mais

    Tempo de leitura: 7 minutos
    08/08/2026