Funções em Python: o que eu aprendi na marra
Você define uma função para não repetir código. Isso é óbvio, mas a parte que ninguém explica direito é quando você começa a passar argumentos e o negócio trava porque esqueceu de declarar um parâmetro padrão ou misturou posicionais com nomeados. Eu passei duas semanas debugando isso no primeiro projeto grande que fiz. Na prática, a estrutura básica é simples. Você escreve def, põe o nome, abre parênteses, coloca os argumentos se tiver, fecha dois-pontos e pronto. O código que vem depois, indentado, é o corpo da função. Quando quer usar, chama pelo nome com os parâmetros que ela espera. Se não passar nada e ela não tiver default, dá erro de TypeError na hora.
O que é definicao de funcao no dia a dia
Muita gente acha que definir função é só juntar um monte de linha pra executar depois. O problema é que tem regra de escopo que mata todo mundo novato. Variável criada dentro da função não existe fora. Variável criada fora, você consegue ler dentro, mas se tentar reescrever, o Python acha que é variável local e dá UnboundLocalError. Eu levei umas cinco tentativas pra entender isso sem chorar. Tem também a questão dos valores padrão. Se você colocar uma lista como argumento default, tipo def minha_funcao(itens=[]):, toda vez que chamar sem passar o parâmetro, a mesma lista vai acumulando valores. Isso acontece porque o default é avaliado uma vez só, na definição, não na chamada. A solução é usar None como default e criar a lista dentro do corpo. Parece besteira, mas já vi gente perder horas por causa disso.
👉 Clique no botão abaixo para saber mais sobre o assunto!
O que eu descobri na prática é que a maior parte dos bugs não está na definição em si, mas no que acontece depois. Argumentos mutáveis, referência a variáveis globais, funções que retornam outras funções. Tudo isso parece avançado, mas é o Básico que todo mundo esbarra no segundo mês. Também tem o caso dos *args e kwargs. Muita gente evita porque parece complexo, mas na verdade são só formas de passar quantidade variável de argumentos. *args vira uma tupla, kwargs vira um dicionário. Usei isso num sistema de logging onde os usuarios podiam passar configurações opcionais sem eu precisar criar dez parâmetros na assinatura. Ficou mais limpo e flexible.
Outro ponto que as pessoas ignoram: documentação dentro da função. Colocar docstring não é só formalismo, é o que te salva quando volta no código seis meses depois e não lembra pra que servia aquele parâmetro. Eu escrevi uma função com oito argumentos e dois anos depois gastei meia hora entendendo o que cada um fazia porque não tinha documentação. From then on, todo código meu tem pelo menos uma linha explicando o que cada parametro faz. Se tiver que dar uma dica prática, é essa: teste sua função com os casos extremos antes de achar que está pronta. Passar None quando espera string, lista vazia, número negativo. O Python não reclama na definição, mas na execução pode quebrar feio. Leva cinco minutos pra testar e economiza horas de debugging depois.