Argumentos Padrão Mutáveis
Quando você combina argumentos mutáveis com argumentos padrão em Python, isso pode levar a resultados inesperados.
Vamos ilustrar isso com um exemplo simples. Suponha que você é um professor e quer criar uma função para registrar as notas dos alunos em diferentes tarefas. Você deseja usar uma lista para acompanhar essas notas. Então, você poderia inicialmente escrever algo assim:
def record_score(new_score, score_list=[]):
score_list.append(new_score)
return score_list
print(record_score(95)) # [95]
print(record_score(85)) # [95, 85]
Parece que isso funcionaria bem. A função
record_score
recebe uma nota e uma lista. Se nenhuma lista for fornecida, ela usa uma vazia (o score_list=[]
na definição da função).Quando você chama
record_score(95)
, parece que a função está funcionando corretamente – retorna uma lista com a nota 95. Mas quando você chama record_score(85)
, a função retorna uma lista com 95 e 85. É como se a função lembrasse da lista da última vez que foi chamada.Isso pode deixá-lo intrigado. Na maioria das linguagens de programação, quando uma função termina, todas as suas variáveis locais (como
score_list
) são descartadas e esquecidas. Na próxima vez que a função é chamada, ela começa do zero.Mas em Python, o comportamento é diferente quando um objeto mutável é usado como argumento padrão. O Python cria o argumento padrão apenas uma vez, quando a função é definida. Portanto, toda vez que você chama
record_score
sem fornecer uma lista, o Python usa a mesma lista que foi criada na primeira vez que a função foi definida. Se você modifica essa lista (adicionando uma nota), a modificação permanece na próxima vez que a função é chamada.Assim, na nossa função, o
score_list
é compartilhado entre todas as chamadas da função em que não fornecemos nossa própria lista. É por isso que as notas estão se acumulando em nosso exemplo.Isso não é o que queríamos! Queríamos que cada chamada a
record_score
começasse com uma lista vazia, a menos que fornecêssemos nossa própria lista.Para evitar isso, uma prática comum é usar
None
como valor padrão para argumentos que possam ser mutáveis. Então, dentro da função, você pode criar um novo objeto mutável se o argumento for None
. Veja como você poderia escrever a função record_score
para evitar o problema:def record_score(new_score, score_list=None):
if score_list is None: # Se nenhuma lista foi fornecida,
score_list = [] # crie uma nova
score_list.append(new_score)
return score_list
print(record_score(95)) # [95]
print(record_score(85)) # [85]
Nesta versão corrigida, cada chamada a
record_score
que não fornece sua própria lista recebe uma lista nova. Assim, as notas não são compartilhadas entre as chamadas da função.💡
Portanto, a principal lição é a seguinte:
Argumentos padrão mutáveis em Python podem levar a comportamentos inesperados porque são criados apenas uma vez, e o mesmo objeto é usado toda vez que a função é chamada. Isso pode não ser o que você deseja, especialmente quando modifica o objeto mutável. Para evitar esse problema, você pode usar
None
como valor padrão e criar um novo objeto na função, se necessário.