## É 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/