Qualquer pessoa que mexa no Python por tempo suficiente foi mordida (ou rasgada em pedaços) pelo seguinte problema:
def foo(a=[]):
a.append(5)
return a
Novatos Python seria de esperar esta função para retornar sempre uma lista com apenas um elemento: [5]
. O resultado é muito diferente e muito surpreendente (para um iniciante):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
Um gerente meu teve seu primeiro encontro com esse recurso e o chamou de "uma falha dramática no design" da linguagem. Respondi que o comportamento tinha uma explicação subjacente, e é realmente muito intrigante e inesperado se você não entende os aspectos internos. No entanto, não fui capaz de responder (a mim mesmo) à seguinte pergunta: qual é o motivo para vincular o argumento padrão na definição da função e não na execução da função? Duvido que o comportamento experiente tenha um uso prático (quem realmente usou variáveis estáticas em C, sem erros de criação?)
Editar :
Baczek fez um exemplo interessante. Juntamente com a maioria dos seus comentários e os de Utaal em particular, eu elaborei ainda mais:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
Para mim, parece que a decisão de design foi relativa a onde colocar o escopo dos parâmetros: dentro da função ou "junto" com ela?
Fazer a ligação dentro da função significaria que x
está efetivamente ligado ao padrão especificado quando a função é chamada, não definida, algo que apresentaria uma falha profunda: a def
linha seria "híbrida" no sentido de que parte da ligação (de o objeto da função) aconteceria na definição e parte (atribuição de parâmetros padrão) no tempo de chamada da função.
O comportamento real é mais consistente: tudo nessa linha é avaliado quando essa linha é executada, ou seja, na definição da função.
[5]
" Eu sou um novato em Python e não esperaria isso, porque obviamente foo([1])
retornarei [1, 5]
, não [5]
. O que você quis dizer é que um novato espera que a função chamada sem parâmetro sempre retorne [5]
.