# Funções em Python: def, return, argumentos, *args e **kwargs, lambda e anotações de tipo

URL: https://skillaria.top/pt/guides/python/funcoes-python-def-return

Função em Python é um bloco de código com nome, declarado pela palavra def, chamado pelo nome com parênteses e que devolve o resultado por meio de return; sem return a função devolve None. Os argumentos são passados por posição ou pelo nome, *args reúne os valores posicionais extras em uma tupla, **kwargs — os nomeados em um dicionário, e lambda cria uma função anônima curta com uma única expressão.

Uma função em Python é um trecho de código com nome, que pode ser chamado quantas vezes for preciso com dados diferentes. Ela é declarada com a palavra `def`, recebe valores por meio de parâmetros e devolve o resultado com `return`. As funções são a principal forma de transformar um script longo em um conjunto de etapas claras e testáveis.

## Como declarar uma função: def python

A declaração de uma função começa com `def`, depois vêm o nome, os parâmetros entre parênteses e os dois-pontos. O corpo é escrito com recuo de quatro espaços — o recuo em Python não é enfeite, é parte da sintaxe.

```
def greet(name):
    """Devolve uma saudação para o usuário."""
    return f"Olá, {name}!"

print(greet("Ana"))   # Olá, Ana!
```

A string entre aspas triplas logo após o cabeçalho é a docstring, a documentação da função. Ela é exibida por `help(greet)` e pelas dicas do editor. Os nomes de funções seguem por convenção a PEP 8 e são escritos em snake_case: `add_expense`, `get_rate`.

A linha `def greet(name):` é chamada de assinatura da função: nome mais lista de parâmetros (e anotações, se houver). Pela assinatura, quem lê entende como chamar a função sem olhar o corpo.

## O que faz o return em Python

`return` encerra a função e entrega um valor a quem a chamou. O código depois de um `return` já executado não roda. Se não houver `return`, ou se ele vier sem valor, a função devolve `None`.

```
def area(w, h):
    w * h          # resultado calculado e descartado

print(area(3, 4))  # None

def area(w, h):
    return w * h

print(area(3, 4))  # 12
```

Um `return` esquecido é um dos erros mais comuns de quem está começando: a função «funciona», mas devolve `None`, e o problema aparece uma linha depois. Dá para devolver vários valores — na prática isso é uma tupla só, que pode ser desempacotada:

```
def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 1, 9])
print(low, high)   # 1 9
```

O `return` antecipado ajuda a evitar aninhamento excessivo: primeiro tratamos os casos especiais, depois escrevemos a lógica principal.

```
def discount(price, is_member):
    if price  limit    # ler a global — pode

def raise_limit():
    global limit
    limit = 2000             # sem global seria criada uma variável local
```

Na prática, `global` é melhor evitar: uma função que altera estado externo é difícil de testar. É mais seguro receber o valor como argumento e devolver o resultado.

## Funções aninhadas e closures

Uma função pode ser declarada dentro de outra. A função interna enxerga as variáveis da externa mesmo depois de a externa ter terminado — isso é um closure (fechamento). Para alterar essa variável usa-se `nonlocal`.

```
def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter()
print(c(), c(), c())   # 1 2 3
```

Closures estão na base dos decoradores e das fábricas de funções.

## Função também é objeto

Em Python a função é um objeto comum: pode ser guardada em uma variável, passada a outra função, devolvida por uma função e armazenada em um dicionário. Ela tem atributos: `__name__`, `__doc__`, `__defaults__`, `__annotations__`.

```
def double(x):
    return x * 2

f = double
print(f(5), f.__name__)                # 10 double
print(list(map(double, [1, 2, 3])))   # [2, 4, 6]
```

## Lambda em Python: funções anônimas

A função lambda é uma função curta sem nome, cujo corpo é uma única expressão. O resultado da expressão é devolvido automaticamente; escrever `return` não é permitido.

```
square = lambda x: x ** 2
print(square(4))   # 16

expenses = [("Café", 250), ("Táxi", 600), ("Almoço", 450)]
expenses.sort(key=lambda e: e[1], reverse=True)
print(expenses)  # [('Táxi', 600), ('Almoço', 450), ('Café', 250)]

print(list(filter(lambda n: n % 2 == 0, range(10))))  # [0, 2, 4, 6, 8]
```

Lambdas em Python são adequadas como argumento curto para `sorted`, `max`, `map`, `filter`. Atribuir lambda a uma variável, como `square` acima, a PEP 8 não recomenda: se a função precisa de nome, escreva `def` — assim ela terá um `__name__` normal no traceback e lugar para a docstring.

|  | def | lambda |
| --- | --- | --- |

| Nome | tem | não tem (`<lambda>`) |

| Corpo | qualquer número de instruções | uma expressão |

| return | explícito | implícito |

| Docstring, anotações | sim | não |

| Onde cabe | em qualquer lugar | key curto ou callback |

## Anotações de tipo: dicas, não verificações

As anotações descrevem os tipos esperados dos parâmetros e do resultado. O próprio Python não as verifica durante a execução: uma função com `x: int` aceita tranquilamente uma string. Quem verifica as anotações são ferramentas externas — mypy, pyright, ty — e o editor, que destaca o erro antes mesmo de o programa ser executado.

```
def add_expense(title: str, amount: float, category: str = "outros") -> dict[str, object]:
    return {"title": title, "amount": amount, "category": category}

def area(w: float, h: float) -> float:
    w * h   # mypy: Missing return statement
```

Para rodar a verificação sem instalar nada, use `uvx mypy .`. O exemplo acima mostra a utilidade das anotações: um `return` esquecido com `-> float` é apontado pelo analisador imediatamente.

A partir do Python 3.12 (PEP 695) funções genéricas são escritas sem `TypeVar`: o parâmetro de tipo vai entre colchetes, e um apelido de tipo é declarado com a palavra `type`.

```
def first[T](xs: list[T]) -> T:
    return xs[0]

type Money = int | float
```

No Python 3.14 (PEP 649) as anotações passaram a ser preguiçosas: elas são calculadas no primeiro acesso, por isso é possível mencionar uma classe declarada mais abaixo sem aspas, e `from __future__ import annotations` não é mais necessário.

## «Não foi passado» ou «foi passado None»: sentinel no 3.15

O valor padrão `None` não permite distinguir «o argumento não foi passado» de «foi passado None de propósito». Durante anos isso era resolvido com um marcador improvisado:

```
_MISSING = object()

def get_rate(currency, default=_MISSING):
    rates = {"USD": 90.5}
    if currency in rates:
        return rates[currency]
    if default is _MISSING:
        raise KeyError(currency)
    return default
```

No Python 3.15 apareceu a função embutida `sentinel` (PEP 661): `MISSING = sentinel("MISSING")` cria um marcador único com uma representação legível, que continua sendo ele mesmo ao ser copiado, é serializado pelo pickle e pode ser usado em uma anotação como `float | MISSING`. Em versões antigas continua valendo o recurso com `object()`.

## Erros típicos com funções

- **Esqueceram o return** — a função devolve `None`.
- **Esqueceram os parênteses** — `print(greet)` mostra o objeto da função, e não o resultado da chamada.
- **Valor padrão mutável** — uma lista compartilhada por todas as chamadas.
- **Número errado de argumentos** — `TypeError: greet() missing 1 required positional argument: 'name'`.
- **Nome igual ao de um embutido** — uma função chamada `list` ou `sum` oculta a função original.

## Resumo

Funções em Python são declaradas com `def`, devolvem o resultado com `return` e recebem argumentos por posição ou pelo nome. `*args` e `**kwargs` dão flexibilidade, `/` e `*` — rigor na chamada, o lambda — brevidade para funções descartáveis, e as anotações de tipo, junto com o mypy, pegam erros antes da execução. No curso de Python esse tema é praticado no dia a dia: o controle de gastos é dividido em funções com anotações e verificado pelo mypy.

## FAQ

**Qual é a diferença entre parâmetro e argumento?**

Parâmetro é o nome na declaração da função, e argumento é o valor concreto passado na chamada. Em def greet(name) o name é o parâmetro, e em greet("Ana") a string "Ana" é o argumento.

**Dá para chamar uma função antes de declará-la?**

No nível do módulo, não: a linha def precisa ser executada antes da chamada, senão ocorre NameError. Mas dentro de outra função é possível chamar uma função declarada mais abaixo, desde que a chamada aconteça depois da declaração.

**Quantos valores uma função pode devolver?**

Formalmente, um só, mas esse valor pode ser uma tupla: return a, b devolve uma tupla de dois elementos, que é desempacotada como x, y = f().

**As anotações de tipo são obrigatórias?**

Não, o Python funciona sem elas. Mas em código lido por outras pessoas elas facilitam a manutenção e permitem que mypy ou pyright encontrem erros antes da execução.

**Posso usar if dentro de um lambda?**

Só uma expressão condicional: lambda x: "par" if x % 2 == 0 else "ímpar". Instruções, laços e atribuições não são permitidos dentro de um lambda.


---
Source: Skillaria.Top (https://skillaria.top)
