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

    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    filecmp no Python: compare arquivos e pastas

    Aprenda filecmp no Python para comparar arquivos e pastas, usar shallow, dircmp, cmpfiles, cache e hashes de integridade.

    Ler mais

    Tempo de leitura: 7 minutos
    03/08/2026
    Terminal de comandos representando parsing seguro com shlex no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    shlex no Python: comandos e argumentos seguros

    Aprenda shlex no Python para separar comandos, tratar aspas, usar quote e join e reduzir riscos de injeção ao executar

    Ler mais

    Tempo de leitura: 7 minutos
    02/08/2026
    Banco de dados local representando persistência com shelve no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    shelve no Python: persistência simples

    Aprenda shelve no Python para persistir objetos, atualizar dados mutáveis, evitar riscos de pickle e saber quando migrar para SQLite.

    Ler mais

    Tempo de leitura: 5 minutos
    01/08/2026
    Documentos de texto representando comparação de versões com difflib no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    difflib no Python: compare textos e arquivos

    Aprenda difflib no Python para comparar textos, medir similaridade, criar diffs unificados, relatórios HTML e sugestões de nomes.

    Ler mais

    Tempo de leitura: 7 minutos
    01/08/2026
    Painel de gráficos representando análise estatística de dados no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    statistics no Python: análise de dados

    Aprenda statistics no Python para média, mediana, desvio padrão, quantis, correlação, regressão, NormalDist e KDE.

    Ler mais

    Tempo de leitura: 8 minutos
    31/07/2026
    Gráficos de frações representando números racionais exatos no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    fractions no Python: números racionais

    Aprenda fractions no Python para cálculos racionais exatos, simplificação, limit_denominator, formatação e conversões seguras.

    Ler mais

    Tempo de leitura: 7 minutos
    31/07/2026