Capítulo 17, Básico
Funções
Uma função dá nome a um pedaço de lógica. Escrever boas funções é o que separa um script que funciona de um programa que dá para manter.
Código deste capítulo: basico/cap17_funcoes.py
Definir, chamar e devolver
Uma função se define com def, recebe parâmetros e devolve um valor com return. Se não houver return, ela devolve None:
def saudacao(nome):
"""Devolve uma saudação."""
return f"Olá, {nome}!"
def sem_retorno():
pass
print(saudacao("Ana"))
print(sem_retorno())
Olá, Ana!
None
Uma confusão comum: print mostra na tela, return devolve o valor para quem chamou. Uma função que só imprime não pode ter o resultado usado em outra conta.
Parâmetros e argumentos
Parâmetro é o nome na definição. Argumento é o valor passado na chamada. Há quatro formas de passar:
- Posicional: a ordem importa.
- Nomeada:
nome=valor, em qualquer ordem. - Padrão: o parâmetro tem um valor caso não seja passado.
- Somente posicional (
/) e somente nomeado (*): você controla como a função pode ser chamada.
def criar_usuario(nome, /, email, *, ativo=True):
return {"nome": nome, "email": email, "ativo": ativo}
print(criar_usuario("Ana", "ana@exemplo.com"))
print(criar_usuario("Bia", email="bia@exemplo.com", ativo=False))
try:
criar_usuario(nome="Caio", email="c@exemplo.com")
except TypeError as erro:
print(erro)
{'nome': 'Ana', 'email': 'ana@exemplo.com', 'ativo': True}
{'nome': 'Bia', 'email': 'bia@exemplo.com', 'ativo': False}
criar_usuario() got some positional-only arguments passed as keyword arguments: 'nome'
Eu uso parâmetros somente nomeados (depois do *) para opções booleanas, porque formatar(texto, True) não diz nada e formatar(texto, maiusculo=True) diz tudo.
*args e **kwargs
Para aceitar uma quantidade variável de argumentos, *args junta os posicionais em uma tupla e **kwargs junta os nomeados em um dicionário. Na chamada, o mesmo símbolo faz o caminho inverso: desempacota:
def somar(*numeros):
return sum(numeros)
def descrever(**atributos):
for chave, valor in atributos.items():
print(f"{chave}: {valor}")
print(somar(1, 2, 3, 4))
descrever(nome="Ana", cidade="Recife")
valores = [10, 20, 30]
print(somar(*valores))
dados = {"nome": "Bia", "cidade": "Natal"}
descrever(**dados)
10
nome: Ana
cidade: Recife
60
nome: Bia
cidade: Natal
Vários valores de retorno
Uma função pode devolver uma tupla, e quem chama desempacota na hora:
def minimo_maximo(numeros):
return min(numeros), max(numeros)
menor, maior = minimo_maximo([4, 8, 2, 9])
print(menor, maior)
2 9
Funções são objetos
Em Python, uma função é um valor como qualquer outro: pode ser guardada em variável e passada como argumento. Essa ideia é a base dos decoradores e da programação funcional que vêm no nível intermediário:
def aplicar(funcao, valor):
return funcao(valor)
print(aplicar(len, "python"))
print(aplicar(str.upper, "python"))
6
PYTHON
Documentação e type hints
A docstring explica o contrato. As anotações de tipo (type hints) o tornam legível por ferramentas. O Python não verifica as anotações ao executar:
def soma(a: int, b: int) -> int:
"""Soma dois inteiros e devolve o resultado."""
return a + b
print(soma(2, 3))
print(soma("a", "b"))
5
ab
A segunda chamada funciona e junta duas strings, apesar de a anotação dizer int. Quem verifica é uma ferramenta externa, como o mypy, que eu apresento no nível intermediário.
Exercício 1
Média de quantos números quiser
Escreva media(*numeros) que devolva a média aritmética.
Exercício 2
Nome completo com opção
Escreva formatar_nome(nome, sobrenome, *, maiusculo=False).