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.

To check your solution you need to sign in
Sign in to continue