Chapter 17, Basic
Functions
A function names a piece of logic. Writing good functions is what separates a working script from a maintainable program.
Code for this chapter: basico/cap17_funcoes.py
Define, call, and return
A function is defined with def, receives parameters and returns a value with return. If there is no return, it returns 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
. A common confusion: print prints to the screen, return returns the value to the caller. A function that only prints cannot have its result used in another calculation.
Parameters and arguments
Parameter is the name in the definition. Argument is the value passed in the call. There are four ways to pass:
- Positional: the order matters.
- Named:
nome=valor, in any order. - Default: the parameter has a value if not passed.
- Only positional (
/) and only named (*): you control how the function can be called.
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'
I use only named parameters (after the *) for boolean options, because formatar(texto, True) says nothing and formatar(texto, maiusculo=True) says everything.
*args and **kwargs
To accept a variable number of arguments, *args collects the positional ones into a tuple and **kwargs collects the named ones into a dictionary. In the call, the same symbol does the reverse: unpacks:
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
Multiple return values
A function can return a tuple, and the caller unpacks it right away:
def minimo_maximo(numeros):
return min(numeros), max(numeros)
menor, maior = minimo_maximo([4, 8, 2, 9])
print(menor, maior)
2 9
Functions are objects
In Python, a function is a value like any other: it can be stored in a variable and passed as an argument. This idea is the basis of decorators and functional programming that come in the intermediate level:
def aplicar(funcao, valor):
return funcao(valor)
print(aplicar(len, "python"))
print(aplicar(str.upper, "python"))
6
PYTHON
Documentation and type hints
The docstring explains the contract. Type annotations (type hints) makes it readable by tools. Python does not check the annotations at runtime:
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
The second call works and concatenates two strings, even though the annotation says int. What checks is an external tool, like mypy, which I introduce at the intermediate level.
Exercise 1
Average of as many numbers as you want
Write media(*numeros) that returns the arithmetic mean.
Exercise 2
Full name with option
Write formatar_nome(nome, sobrenome, *, maiusculo=False).