Parâmetros mutáveis preservam estado entre chamadas Python
Um argumento padrão é avaliado quando a função é definida; a mesma lista pode ser reutilizada.
DoesItHold Editorial · · revisado em · guide-python-defaults-001
Resposta direta
Use None como sentinela e aloque o valor mutável dentro da função.
O Python avalia expressões padrão uma vez, quando a instrução def é executada. Uma lista, um dicionário ou um conjunto criado ali passa a fazer parte do objeto da função e é reutilizado sempre que a chamada omite o argumento. Alterá-lo muda o que a próxima chamada recebe.
Esse estado surpreendente é determinístico, não aleatório. Reproduza com duas chamadas que omitem o argumento e compare os valores retornados e suas identidades. O experimento separa o padrão compartilhado de um estado armazenado em outro lugar.
- 01Definiçãouma lista padrão é alocada
- 02Chamada Aa lista compartilhada vira ['a']
- 03Chamada Ba mesma lista vira ['a', 'b']
- 04SentinelaNone cria uma lista por chamada
Exemplo mínimo
Região de código com rolagem
def collect(value, items=[]):
items.append(value)
return itemsdef collect(value, items=None):
if items is None:
items = []
items.append(value)
return itemsO que muda: Duas chamadas que omitem o argumento deixam de compartilhar um objeto; uma coleção fornecida explicitamente continua sendo alterada como solicitado.
Método de depuração
Chame a função duas vezes sem o argumento, compare identidades e mova a alocação para o fluxo da chamada.
- Reproduza com duas chamadas que omitem o argumento mutável.
- Inspecione o padrão por __defaults__ e compare as identidades dos objetos.
- Troque o padrão mutável por None e aloque somente quando o argumento for None.
- Teste tanto a omissão quanto uma coleção vazia fornecida explicitamente.
Correção incorreta comum
Copiar a lista no return ainda permite mutação durante a chamada e esconde a propriedade do objeto. Usar items = items or [] também substitui uma lista vazia válida fornecida por quem chamou.
Limites e casos especiais
Um padrão mutável persistente pode ser intencional para cache, mas esse estado fica implícito, compartilhado e difícil de reiniciar. Prefira um objeto de cache explícito ou um decorador padrão para deixar propriedade e ciclo de vida visíveis.