## É hora da história! Imagine que o Branda chegou para você e disse: - Preciso de uma função que retorne as espécies favoritas de cada programador de CORP! Pensando nisso, você escreve o seguinte código: Ele vai receber o nome do programador, e baseado nisso, retornar as espécies favoritas. Todavia, se você quiser, pode já fornecer algumas espécies que você sabe que o programador gosta. ```python def get_favorite_species(coder, favorites=[]): if coder in ['kamm', 'veloso', 'mentz']: favorites.append('dairy') if coder in ['gaspa', 'cuchi']: favorites.append('layers') if coder == 'mary': favorites.append('broiler') return favorites ``` ## Show! Finalizado. É hora de testar: > ​​ > Bora começar por mim! Eu já queria dizer de cara: Amo porquinhos! Bora ver o que acontece. > ```python > print(get_favorite_species('kamm', favorites=['swine'])) > > ['swine', 'dairy'] > ``` > Tudo parece estar funcionando! Bora codar mais. Agora, vou adicionar o Gaspa! Não sei nenhuma espécie favorita dele... > > ```python > print(get_favorite_species('kamm', favorites=['swine'])) > > ['swine', 'dairy'] > > print(get_favorite_species('gaspa')) > > ['layers'] > ``` > Funcionou com o gaspa! Bora testar com a mary! > > ```python > print(get_favorite_species('kamm', favorites=['swine'])) > > ['swine', 'dairy'] > > print(get_favorite_species('gaspa')) > > ['layers'] > > print(get_favorite_species('mary')) > > ['layers', 'broiler'] > ``` > > Xiii... como assim a Mary gosta de layers? Esse não era o gaspa? Deveria ser apenas broiler... >​ ## Explicação: Ao definir a função `get_favorite_species`, decidimos fornecer um valor default para o argumento `favorites`. Então, quando você rodar o seu arquivo `.py` pela primeira vez (ou subir seu `Django/Flask`), ele vai salvar um "ponteiro" para essa lista chamada `favorites`. (Ou seja, uma única referência para `favorites` que vai ser usada toda vez que essa função ser chamada) Visto isso, vamos entender o que acontece em cada uma dessas linhas: ```python """ Nessa linha, fornecemos um 'favorites' já conhecido. Falando sobre a parte técnica, isso irá sobreescrever o favorites da assinatura da função. Ou seja, não será usada a referência original de favoritas iniciado vazio, e sim uim objeto que nós estamos fornecendo. Como resultado, temos o output esperado. """ print(get_favorite_species('kamm', favorites=['swine'])) """ Nessa linha, não fornecemos nenhum 'favorites'. Isso significa que iremos utilizar internamente o 'favorites' default (Aquela referência a uma lista vazia, criada quando vc subiu seu arquivo .py) Inicialmente, de fato ela é vazia. Então, anteriormente o favorites=[], irá ser MUTADO para ['layers']. Todavia, o pronto crítico é: Essa lista era uma REFERÊNCIA. Ao terminar a execução dessa linha, a lista 'favorites' AINDA terá ['layers'] dentro. """ print(get_favorite_species('gaspa')) """ Nessa linha, não fornecemos nenhum 'favorites'. Isso significa que iremos utilizar internamente o 'favorites' default. Esse, por sua vez, foi mutado anteriormente, e é: ['layers'] Ao adicionar mais uma espécie, (a da mary), temos o resultado estranho. """ print(get_favorite_species('mary')) ``` --- ## Solução ```python def get_favorite_species_fixed(coder, favorites=None): if not favorites: favorites = [] if coder in ['kamm', 'veloso', 'mentz']: favorites.append('dairy') if coder in ['gaspa', 'cuchi']: favorites.append('layers') if coder == 'mary': favorites.append('broiler') return favorites ``` A solução é: **Devemos ter cuidado ao usar objetos mutáveis como argumentos default.** Nesse caso, usandos uma lista (que é mutável), mas esse erro também iria ocorrer para dicionários. Você pode testar o código aqui: - [Código das duas funções](https://replit.com/@ViniciusKammrad/ExemplosMutavel#main.py) Documentações: - https://florimond.dev/en/posts/2018/08/python-mutable-defaults-are-the-source-of-all-evil/ - https://docs.python-guide.org/writing/gotchas/