Unidade 4 · receitas da casa

Receitas da casa

Quando o mesmo gesto se repete — etiqueta, área da mesa, total do pão — você escreve a receita uma vez. def, parâmetro, return, escopo, ponto de entrada.

Nesta unidade Até aqui você falou com o terminal, decidiu a via e girou a fila. Agora fatia o trabalho: uma função por gesto. Na unidade 3 o loop já cansava a mão; aqui o loop mora dentro da receita.

Não no primeiro recado

No recado você imprime. No crachá, guarda. Na via, decide. Na fila, repete. Copiar print("VIA") três vezes já doeu — e ainda não tinha nome para “pergunte um N positivo”. Função existe para isso: um gesto, um nome, devolve ou mostra, e o resto do arquivo só chama.

Se tivesse vindo na unidade 1, você fatiaria um programa de uma linha. Agora há o que fatiar: loop, input, conta, recado. A receita só vale a pena quando a mão já copiou.

Receita na cozinha, não na hora do palpite

Arquivo etiqueta.py. A função etiqueta recebe um texto e o imprime entre linhas. Parâmetro é o nome do ingrediente na receita; argumento é o valor na hora de usar.

def etiqueta(texto):
    print("---")
    print(texto)
    print("---")

etiqueta("Arquivo morto")

Dois-pontos no fim do def. Tudo indentado (4 espaços) pertence à função. Sem indentação o Python recusa — a linguagem usa recuo no lugar de chaves { }.

No editor da unidade, Tab insere quatro espaços, como no dia a dia. Depois de uma linha que termina em :, Enter já começa recuado. Misture tab e espaço no mesmo bloco e o interpretador reclama; fique nos espaços.

Se você chama a função antes de defini-la, no fluxo de cima para baixo: NameError. Defina primeiro, use depois — ou organize o arquivo com um ponto de entrada no fim.

4.A · def

Defina etiqueta(texto) que imprime o parâmetro (pelo menos um print).

Primeira linha: def etiqueta(texto):
Abaixo, indentado, print(texto) ou print com f-string.
Exemplo:
def etiqueta(texto):
print(texto)

Como passar o ingrediente

Posicional: a ordem dos parênteses é a ordem da receita. area(3, 2) — 3 entra no primeiro parâmetro, 2 no segundo.

Nomeado: você chama pelo nome, a ordem pode mudar. area(altura=2, largura=3). Já vimos isso em sep= e end=.

Valor padrão: def etiqueta(texto, marca="-"). Se ninguém passar marca, vale o traço. Quem chama pode sobrescrever: etiqueta("urgente", marca="*").

Docstring logo abaixo do def, indentada, entre """: uma frase do que a função faz. Ferramentas e humanos leem. Não substitui um nome claro.

def area(largura, altura):
    """Área de um retângulo em unidades quadradas."""
    return largura * altura

Devolver, não só mostrar

Imprimir é efeito na tela. Calcular área de um retângulo (etiqueta adesiva, box de produto) precisa entregar o número para o resto do programa usar — somar, arredondar, mandar para outro print.

def area(largura, altura):
    return largura * altura

m2 = area(3, 2)
print(f"{m2} m²")

Sem return, a conta acontece e some; quem chamou recebe None. Três contas equivalentes para potência, se um dia precisar: n * n, n ** 2, pow(n, 2) — aqui o caso natural é só o produto da largura pela altura.

4.B · return

Escreva area(largura, altura) que devolve o produto (não imprima dentro da função).

print aqui seria efeito colateral. Quem quer mostrar é quem chama.
return largura * altura
Solução:
def area(largura, altura):
return largura * altura

O arquivo precisa de um disparo

Definir main não executa nada. def só registra a receita. Alguém precisa chamar main() — em geral no fim do arquivo, ou dentro do idioma abaixo.

Ponto de entrada idiomático em Python — o arquivo só “dispara” quando rodado direto, não quando importado:

def area(largura, altura):
    return largura * altura

def main():
    print(area(3, 2))

if __name__ == "__main__":
    main()

__name__ vale "__main__" quando o arquivo é o que você passou para python. Assim as funções podem ser reaproveitadas em outro arquivo sem executar o teste sozinhas.

4.C · chamar main

Você escreveu def main(): com um print dentro. O arquivo roda e a tela fica vazia. Por quê?

Receita na gaveta não cozinha sozinha.
No fim: main() ou if __name__ == "__main__": main()
Solução: falta a chamada.

Gaveta de um cômodo só

Escopo: variável criada dentro de uma função só existe ali. Se capa faz titulo = "relatório" e etiqueta tenta print(titulo) sem receber parâmetro, NameError. A ponte é o argumento: etiqueta(titulo) de um lado, def etiqueta(texto) do outro. Os nomes podem ser diferentes; o valor é que viaja.

Métodos tipo .strip() continuam sendo de string: se sua função devolve número, não tem o que stripar.

4.D · escopo

titulo é criado dentro de capa(). etiqueta() sem parâmetros faz print(titulo). Resultado?

Arquivo igual ≠ memória compartilhada entre funções.
Passe o valor na chamada: etiqueta(titulo).
Solução: NameError de escopo.

Devolver True ou False sem novela

Uma função que só pergunta “é par?” pode devolver a expressão crua:

def e_par(n):
    return n % 2 == 0

Equivalente mais falado: return True if n % 2 == 0 else False. Os dois estão certos; o primeiro é mais curto. O if numa só linha (ternário) existe; não abuse se a leitura sofrer. A comparação já é um bool.

4.E · return bool

Uma linha de return que devolva se n é par (ternário ou a expressão n % 2 == 0).

Você pode devolver a pergunta inteira. Ela já vale True ou False.
return n % 2 == 0
Solução: return n % 2 == 0 ou return True if n % 2 == 0 else False

Peças que já conhecemos, juntas

get_positivo não existe no Python. Você inventa. Dentro do loop, em vez de break + return lá fora, pode return n direto: sair da função já sai do loop.

def get_positivo():
    while True:
        n = int(input("Quantas vias? "))
        if n > 0:
            return n

def vias(n):
    for _ in range(n):
        print("VIA")

def main():
    vias(get_positivo())

if __name__ == "__main__":
    main()

break ainda vale: sai só do loop; aí você return n depois do while. Os dois caminhos existem.

Oficina · recibo mínimo

Problema da unidade Uma função total(preco, qtd) que return o produto. No ponto de entrada, leia os dois valores (números, unidade 1), chame total e imprima com duas casas. Arquivo: recibo.py.
Oficina 4

Cole o recibo: função com return e um ponto de entrada.

def total(preco, qtd): return preco * qtd
if __name__ == "__main__": lê input, chama total, print
Modelo:
def total(preco, qtd):
    return preco * qtd

if __name__ == "__main__":
    p = float(input("Preço: "))
    q = int(input("Qtd: "))
    print(f"{total(p, q):.2f}")