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.
 
To check your solution you need to sign in
Sign in to continue