functools.Placeholder amplia o poder de functools.partial() ao permitir reservar posições específicas entre os argumentos posicionais. Antes desse recurso, partial() preenchia argumentos sempre da esquerda para a direita. Isso funcionava muito bem quando os valores fixos estavam no começo da assinatura, mas exigia wrappers, lambdas ou adaptações quando você queria deixar o primeiro argumento aberto e fixar um argumento intermediário.
Com Placeholder, você pode declarar explicitamente quais posições deverão ser preenchidas depois. O resultado é uma API mais clara, menor quantidade de código auxiliar e melhor reutilização de funções existentes.
O problema que Placeholder resolve
Considere uma função com três argumentos posicionais. Você deseja fixar o segundo argumento, mas ainda fornecer o primeiro e o terceiro no momento da chamada. Sem um placeholder, uma solução comum seria escrever uma função intermediária ou uma lambda. Isso adiciona uma camada desnecessária, pode esconder a assinatura original e dificulta introspecção.
def registrar(evento, nivel, destino):
return f"{nivel}: {evento} -> {destino}"
# solução tradicional
info_para = lambda evento, destino: registrar(evento, "INFO", destino)
O wrapper funciona, mas seu propósito é apenas reorganizar o preenchimento dos argumentos. Com Placeholder, a intenção fica explícita na construção do partial.
Importação e sintaxe básica
from functools import partial, Placeholder as _
def registrar(evento, nivel, destino):
return f"{nivel}: {evento} -> {destino}"
info_para = partial(registrar, _, "INFO", _)
print(info_para("login", "auditoria.log"))
Cada ocorrência de _ representa uma posição obrigatória a ser preenchida na chamada posterior. Os argumentos recebidos são usados na ordem dos placeholders. Depois que todos forem preenchidos, argumentos posicionais adicionais continuam sendo anexados normalmente.
Placeholder não é um valor comum
O objeto Placeholder tem significado especial apenas dentro de partial() e partialmethod(). Ele não representa None, uma string vazia ou um argumento opcional. É uma marca de posição que precisa ser resolvida. Se a chamada não fornecer argumentos suficientes para todos os placeholders, o Python gera TypeError.
formatar = partial(str.replace, _, "-", " ")
print(formatar("python-avancado"))
Nesse exemplo, o primeiro argumento de str.replace permanece aberto, enquanto os valores antigo e novo são fixados.
Ordem de preenchimento
Os placeholders são preenchidos da esquerda para a direita. Essa regra torna o comportamento previsível mesmo quando existem várias lacunas.
def combinar(a, b, c, d):
return a, b, c, d
modelo = partial(combinar, _, 20, _, 40)
print(modelo(10, 30))
O resultado será (10, 20, 30, 40). O primeiro argumento recebido preenche o primeiro placeholder, e o segundo preenche o próximo.
Partial aninhado
Um partial pode ser usado como base para outro partial. Quando isso acontece, novos argumentos podem preencher placeholders existentes. Você também pode inserir um novo Placeholder para manter determinada posição aberta.
base = partial(combinar, _, 20, _, 40)
com_inicio = partial(base, 10)
print(com_inicio(30))
Essa composição é útil para criar uma família de funções especializadas em etapas, sem duplicar lógica.
Uso em pipelines de dados
Placeholder é especialmente útil quando uma biblioteca espera uma função de um argumento, mas a função original possui vários parâmetros e o valor variável não está na primeira posição.
from functools import partial, Placeholder as _
def entre(minimo, valor, maximo):
return minimo <= valor <= maximo
entre_0_e_100 = partial(entre, 0, _, 100)
print(list(filter(entre_0_e_100, [-5, 10, 120, 80])))
O valor produzido por filter() preenche exatamente a posição marcada. Sem Placeholder, você provavelmente escreveria uma lambda apenas para reorganizar os argumentos.
Integração com sorted e map
O mesmo padrão aparece em map(), sorted(), callbacks e sistemas de eventos. Sempre que uma API entrega um argumento em uma posição incompatível com a função que você deseja reutilizar, Placeholder pode servir como adaptador declarativo.
def normalizar(prefixo, texto, sufixo):
return prefixo + texto.strip().lower() + sufixo
normalizador = partial(normalizar, "[", _, "]")
resultado = list(map(normalizador, [" Python ", " APIs "]))
Placeholder com métodos
Em métodos não vinculados, a instância costuma ocupar o primeiro argumento. Placeholder permite manter a instância aberta e fixar outros parâmetros. Para descritores e métodos definidos em classes, partialmethod() pode ser ainda mais adequado porque preserva o binding de self.
from functools import partialmethod, Placeholder as _
class Cliente:
def enviar(self, mensagem, canal, prioridade):
return mensagem, canal, prioridade
enviar_email = partialmethod(enviar, _, "email", "normal")
Use testes para confirmar a assinatura e o binding esperados, principalmente em hierarquias de classes.
Limitações importantes
Placeholder atua sobre argumentos posicionais. Ele não pode ser usado para preencher valores dentro de keywords do partial. Para argumentos nomeados, continue usando o comportamento tradicional de partial() ou crie uma função adaptadora quando a transformação for mais complexa.
Também não vale a pena substituir toda lambda por partial. Lambdas continuam melhores quando existe transformação, condição, cálculo ou combinação de vários valores. Placeholder é ideal quando o objetivo principal é apenas fixar e reorganizar argumentos.
Legibilidade
Importar Placeholder como _ deixa exemplos compactos, mas o sublinhado também é usado em internacionalização, descarte de valores e shells interativos. Em projetos grandes, considere importar pelo nome completo ou usar um alias mais explícito, como PH.
from functools import Placeholder as PH
A escolha deve seguir as convenções do projeto. O principal é que leitores reconheçam imediatamente a marca de posição.
Compatibilidade de versão
Antes de adotar o recurso, confirme a versão mínima do Python suportada pelo projeto. Bibliotecas distribuídas para versões anteriores podem precisar manter wrappers tradicionais ou implementar uma camada de compatibilidade. Não copie objetos que apenas imitam Placeholder sem compreender as diferenças de comportamento.
Testes recomendados
Teste o caminho normal, argumentos insuficientes, argumentos adicionais, composição de partials e métodos vinculados. Verifique também mensagens de erro e introspecção quando elas fazem parte da experiência pública da API.
def test_intervalo():
assert entre_0_e_100(0)
assert entre_0_e_100(100)
assert not entre_0_e_100(101)
Quando usar
- Ao fixar argumentos intermediários.
- Ao adaptar funções para callbacks de um argumento.
- Ao criar famílias de funções especializadas.
- Ao reduzir wrappers que apenas reorganizam parâmetros.
- Ao preservar a função original em pipelines funcionais.
Quando evitar
- Quando a transformação exige lógica adicional.
- Quando muitos placeholders tornam a chamada difícil de entender.
- Quando a compatibilidade com versões antigas é obrigatória.
- Quando parâmetros nomeados expressam melhor a intenção.
Boas práticas
Prefira funções com assinaturas claras, limite o número de lacunas e dê nomes descritivos aos partials resultantes. Documente a versão mínima do Python e mantenha testes próximos aos casos reais. Placeholder é uma ferramenta de composição, não uma desculpa para conservar assinaturas confusas.
Para aprofundar conceitos relacionados, leia os conteúdos da Academify sobre funções em Python, itertools no Python, generators e list comprehensions.
Conclusão
functools.Placeholder torna partial() mais flexível ao permitir lacunas posicionais explícitas. Ele reduz wrappers artificiais, melhora a reutilização de funções e encaixa bem em callbacks e pipelines. Use o recurso quando a intenção for preencher argumentos em etapas, mantendo a solução simples, testável e legível.







