Pular para o conteúdo principal

Recursão em Python: Conceitos, exemplos e dicas

Aprenda recursão em Python com exemplos, conceitos-chave e dicas práticas. Compreender casos básicos, funções recursivas e quando usar recursão em vez de iteração.
Atualizado 10 de abr. de 2025  · 9 min lido

A recursão é um conceito fundamental na programação e tem uma importância especial em Python. Refere-se à técnica em que uma função chama a si mesma para resolver um problema, dividindo-o em subproblemas menores e gerenciáveis. 

Esse método permite soluções elegantes e concisas, especialmente ao lidar com problemas que envolvem tarefas repetitivas ou estruturas hierárquicas. Em Python, a recursão é usada em uma variedade de aplicações, desde a classificação até os algoritmos que você usa. algoritmos até a passagem de dados complexos.

As soluções recursivas geralmente refletem as definições matemáticas dos problemas, tornando-as intuitivas para aqueles que estão familiarizados com o raciocínio matemático. A beleza da recursão está em sua capacidade de expressar algoritmos complexos em apenas algumas linhas de código, criando soluções que são elegantes e legíveis. No entanto, dominar a recursão exige uma mudança de pensamento em relação às abordagens iterativas mais comuns.

Neste artigo, explorarei o conceito de recursão, como ele funciona em Python e suas aplicações práticas, incluindo uma discussão de problemas comuns e comparações com a iteração. Se você é novo em Python, considere fazer um de nossos cursos, como Introdução ao Python, Conceitos de paradigma de programaçãoou Fundamentos da programação em Python.

O que é recursão em Python?

Em Python, a recursão se refere a uma função que chama a si mesma para resolver um problema. Ele envolve dois componentes essenciais:

  • Caso base: Essa é a condição que encerra a recursão. Sem isso, as chamadas recursivas continuariam para sempre, fazendo com que a função acabasse travando ou esgotando a memória disponível.
  • Caso recursivo: Essa parte da função envolve dividir o problema em partes menores e chamar a função novamente com essas partes menores.

Aqui está uma maneira simples de pensar sobre recursão: imagine uma função que resolve um problema complexo resolvendo versões menores do mesmo problema, chegando a uma solução que não requer mais recursão.

A abordagem recursiva segue a estratégia "dividir para conquistar", dividindo problemas complexos em versões mais simples até chegar a um caso trivial. Essa abordagem geralmente reflete a maneira como pensamos naturalmente sobre a solução de problemas. Por exemplo, ao classificar um baralho de cartas, podemos naturalmente classificar grupos menores e depois combiná-los, que é essencialmente como os algoritmos de classificação recursiva, como merge sort funcionam.

Toda função recursiva deve ter pelo menos um caso base e pelo menos um caso recursivo. O caso base evita a recursão infinita fornecendo uma condição que não exige outras chamadas de função. O caso recursivo reduz o tamanho do problema a cada chamada, garantindo que o caso base seja finalmente alcançado.

Como a recursão funciona em Python?

A recursão funciona permitindo que uma função chame a si mesma com argumentos modificados, resolvendo gradualmente o problema em etapas menores. Para entender isso de forma mais concreta, considere a tarefa de calcular a soma dos números de 1 a num.

Aqui está uma abordagem recursiva simples para calcular a soma:

def sum_recursive(num):
    if num == 1:  # Base case
        return num
    return num + sum_recursive(num - 1)  # Recursive case

print(sum_recursive(3)) # 3 + 2 + 1 
6

Nessa função, o caso base é quando num == 1, que interrompe a recursão. Caso contrário, a função chama a si mesma com num - 1 até atingir o caso base.

Como funciona passo a passo:

  1. sum_recursive(3) Você liga para sum_recursive(2).
  2. sum_recursive(2) Você liga para sum_recursive(1).
  3. sum_recursive(1) retorna 1 (caso básico).
  4. Agora, sum_recursive(2) pode retornar 2 + 1 = 3, e sum_recursive(3) pode retornar 3 + 3 = 6.

Outro exemplo seria uma função recursiva para calcular a potência de um número:

def power(base, exponent):
    if exponent == 0:  # Base case
        return 1
    else:
        return base * power(base, exponent - 1)  # Recursive case

print(power(2, 3))
8

Explicação passo a passo dessa função de potência:

  • power(2, 3) Você liga para power(2, 2).
  • power(2, 2) Você liga para power(2, 1).
  • power(2, 1) Você liga para power(2, 0).
  • power(2, 0) retorna 1 (caso básico).
  • Agora, trabalhando de trás para frente: power(2, 1) retorna 2 * 1 = 2.
  • Em seguida, power(2, 2) retorna 2 * 2 = 4.
  • Por fim, power(2, 3) retorna 2 * 4 = 8.

Quando uma função recursiva é chamada, cada chamada recursiva cria uma nova entrada na pilha de chamadas. Essa pilha mantém o controle de todas as chamadas de função e suas variáveis. Quando o caso base é atingido, a pilha começa a resolver cada chamada na ordem inversa, calculando o resultado final passo a passo.

Para que você entenda esse comportamento da pilha, é fundamental que explique tanto o poder quanto as limitações da recursão em Python. Ele preserva o contexto de forma elegante, mas também pode levar a problemas de memória com recursão profunda.

Implementando o fatorial em Python usando recursão

A função fatorial é um exemplo clássico usado para demonstrar a recursão. O fatorial de um número n, denotado n!, é o produto de todos os números inteiros positivos menores ou iguais a n. Matematicamente:

n! = n × (n − 1) × (n − 2) × … × 1

Recursivamente, a função fatorial pode ser definida como:

n! = n × (n − 1)!

Vamos implementar isso em Python:

def compute_factorial(num):
    if num == 0:  # Base case
        return 1
    return num * compute_factorial(num - 1)  # Recursive case

print(compute_factorial(4)) # 4 * 3 * 2 * 1
24

Explicação passo a passo do código:

  • A função compute_factorial(num) verifica se num == 0 e retorna 1 nesse caso.
  • Caso contrário, ele retorna num * compute_factorial(num - 1), onde a função chama a si mesma com um valor menor de num.

A função fatorial ilustra perfeitamente a elegância da recursão. A própria definição matemática é recursiva, o que torna a implementação do código intuitiva e estreitamente alinhada com o conceito matemático. Esse é um dos pontos fortes da recursão, pois permite que o código expresse diretamente definições matemáticas.

É importante observar que há casos extremos a serem considerados. Por exemplo, o fatorial normalmente só é definido para números inteiros não negativos. Uma implementação robusta pode incluir tratamento de erros para entradas negativas ou verificação de tipo. 

Além disso, para valores grandes de num, a solução recursiva pode levar a um estouro de pilha, que é uma limitação que discutirei em mais detalhes.

Problemas comuns: Como corrigir erros de recursão em Python

Embora a recursão possa ser uma ferramenta poderosa, ela está sujeita a alguns problemas comuns, como:

Exceder a profundidade máxima de recursão

O Python tem um limite de recursão padrão de 1.000 chamadas. Se uma função recursiva chamar a si mesma muitas vezes, será gerado um RecursionError.

Veja como você pode corrigir isso:

Você pode aumentar a profundidade da recursão usando sys.setrecursionlimit(). No entanto, isso não é recomendado, a menos que seja necessário, pois pode causar um estouro de pilha.

import sys  

# Get the current recursion limit
current_limit = sys.getrecursionlimit()
print(f'Current limit: {current_limit}')  

# Set a new recursion limit to 200
new_limit = 200
sys.setrecursionlimit(new_limit)  

# Get the new recursion limit
changed_current_limit = sys.getrecursionlimit()
print(f'Current limit after change: {changed_current_limit}')  
Current limit: 1000
Current limit after change: 200

Caso base ausente

Um caso base ausente ou incorreto fará com que a função recurse infinitamente, levando a um estouro de pilha.

Para corrigi-lo, certifique-se de que seu caso base seja bem definido e alcançável.

Como parar a recursão em Python

A chave para interromper a recursão em Python é definir um caso base adequado. Sem isso, a recursão nunca terminará e resultará em um erro.

Por exemplo, na função fatorial que implementei anteriormente, o caso base era if num == 0, o que interrompe a recursão. Em geral, você precisa garantir que cada função recursiva tenha uma condição sob a qual ela termine.

A elaboração de casos de base eficazes requer uma reflexão cuidadosa. Algumas diretrizes incluem:

  • Identifique a versão mais simples do problema que pode ser resolvida diretamente.
  • Garanta que todos os caminhos recursivos cheguem a um caso base.
  • Teste os casos de borda separadamente para verificar se eles são tratados corretamente.
  • Considere vários casos de base se o problema exigir isso.

Às vezes, as técnicas de programação defensiva são úteis, adicionando proteções contra entradas inválidas ou verificações de tempo de execução para evitar profundidade excessiva de recursão. Por exemplo:

def safe_factorial(num, depth=0, max_depth=100):
    # Check if recursion is too deep
    if depth > max_depth:
        raise ValueError("Maximum recursion depth exceeded")
   
    # Base case
    if num <= 0:
        return 1
   
    # Recursive case with depth tracking
    return num * safe_factorial(num - 1, depth + 1, max_depth)
# Calculate factorial of 5 with default depth limits
result = safe_factorial(5)

print(result) 
120
# Calculate factorial of 5 with depth > max_depth
result = safe_factorial(5, depth=20, max_depth=10)

print(result) 
ValueError: Maximum recursion depth exceeded

Essa abordagem permite que você defina limites personalizados e forneça mensagens de erro mais significativas do que o padrão RecursionError.

Aqui está outro exemplo que demonstra uma maneira diferente de definir casos de base: encontrar o maior divisor comum (GCD) de dois números usando recursão.

O GCD de dois números x e y pode ser calculado usando o algoritmo de Euclides, com o operador de módulo operador de módulo %:

  • Caso básico: Se você tem y == 0, o GCD é x.
  • Caso recursivo: Caso contrário, o GCD de x e y é o mesmo que o GCD de y e x % y.
def find_gcd(x, y):
    # Base case: if y is 0, the GCD is x
    if y == 0:
        return x
    # Recursive case: GCD of y and x % y
    return find_gcd(y, x % y)

print(find_gcd(48, 18))  
6

Recursão vs. Iteração em Python

Tanto a recursão quanto a iteração podem resolver muitos dos mesmos problemas, mas cada uma tem seus prós e contras:

  • A recursão costuma ser mais elegante e mais fácil de entender, especialmente para problemas que têm uma estrutura recursiva natural (por exemplo travessias de árvoresfatoriais, números de Fibonacci).
  • A iteração pode ser mais eficiente porque não envolve a sobrecarga de várias chamadas de função e pode evitar problemas relacionados ao estouro de pilha. As soluções iterativas geralmente são mais eficientes em termos de memória.

Quando usar a recursão:

  • Quando o problema pode ser naturalmente dividido em subproblemas menores.
  • Para problemas que envolvem estruturas de dados hierárquicas, como árvores.
  • Quando a solução em forma recursiva é mais intuitiva e leva a um código mais limpo.
  • Quando a legibilidade do código é priorizada em relação à otimização do desempenho.
  • Ao trabalhar com dados de profundidade desconhecida (como analisar JSON ou XML aninhados).

Quando usar a iteração:

  • Para problemas que exigem tarefas repetitivas sem dividir o problema em subproblemas menores.
  • Para tarefas de desempenho crítico, em que a recursão profunda pode resultar em alto uso de memória.
  • Quando você trabalha com grandes conjuntos de dados que podem exceder o limite de recursão.
  • Quando o uso da memória é a principal preocupação.
  • Para problemas que são naturalmente sequenciais em vez de hierárquicos.

Vamos comparar as implementações recursivas e iterativas do mesmo problema, calculando a soma dos números de 1 a num:

Recursivo:

def sum_recursive(num):
    if num == 1:
        return 1
    else:
        return num + sum_recursive(num - 1)

Iterativo:

def iterative_sum(num):
    total = 0
    for i in range(1, num + 1):
        total += i
    return total

A versão iterativa usa um loop para acumular a soma, enquanto a versão recursiva divide o problema em adicionar n à soma dos números de 1 a num - 1. Embora ambas as soluções funcionem, a versão iterativa será mais eficiente para valores grandes de num, pois não envolve a sobrecarga de várias chamadas de função.

Alguns problemas que são naturalmente recursivos podem ser transformados em soluções iterativas usando uma pilha ou fila para simular as chamadas recursivas. Essa técnica é particularmente útil quando você lida com travessias de árvores ou gráficos.

Exemplos práticos de recursão em Python

A recursão pode ser aplicada a uma variedade de problemas interessantes:

1. Cálculo dos números de Fibonacci

A sequência de Fibonacci é definida recursivamente como:

  • F(0) = 0
  • F(1) = 1
  • F(n) = F(n − 1) + F(n − 2)

Isso fornecerá a seguinte sequência:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,...

Veja como você poderia implementá-lo:

def compute_fibonacci(num):
    if num <= 0:
        return 0
    elif num == 1:
        return 1
    return compute_fibonacci(num - 1) + compute_fibonacci(num - 2)

print(compute_fibonacci(6))
8

No entanto, essa implementação ingênua recalcula os valores várias vezes. Uma abordagem mais eficiente usa a memoização, que armazena resultados computados anteriormente (cache) para evitar cálculos redundantes e reduzir significativamente o tempo de computação:

def optimized_fibonacci(num, cache=None):
    if cache is None:
        cache = {}
    if num in cache:
        return cache[num]
    if num <= 1:
        return num
    cache[num] = optimized_fibonacci(num - 1, cache) + optimized_fibonacci(num - 2, cache)
    return cache[num]

Isso pode ser simplificado ainda mais usando o decorador lru_cache() do módulo functools:

from functools import lru_cache

@lru_cache(maxsize=None)  # Cache all computed values
def cached_fibonacci(num):
    if num <= 1:
        return num
    return cached_fibonacci(num - 1) + cached_fibonacci(num - 2)

2. Percorrendo estruturas de dados aninhadas

A recursão também é útil para trabalhar com estruturas de dados aninhadas, como listas de listas ou objetos JSON. Por exemplo, percorrer uma estrutura de árvore de diretório ou achatar recursivamente uma lista aninhada.

def flatten(nested):
    result = []
    for element in nested:
        if isinstance(element, list):
            result.extend(flatten(element))
        else:
            result.append(element)
    return result

nested_structure = [1, [2, 3], [4, [5, 6]]]

print(flatten(nested_structure))  
[1, 2, 3, 4, 5, 6]

3. Algoritmos de classificação (por exemplo, classificação rápida ou classificação de mesclagem) 

Algoritmos de classificação como quick sort e merge sort dependem muito da recursão. Nesses algoritmos, o problema é dividido em subproblemas menores, que são classificados de forma recursiva.

Aqui está uma implementação simples do quicksort:

def quicksort_algo(array):
    if len(array) <= 1:
        return array
    pivot = array[len(array) // 2]
    lower = [item for item in array if item < pivot]
    equal = [item for item in array if item == pivot]
    greater = [item for item in array if item > pivot]
    return quicksort_algo(lower) + equal + quicksort_algo(greater)

array = [220, 33, 400, 150, 16]

print(quicksort_algo(array))
[16, 33, 150, 220, 400]

Conclusão

A recursão é um conceito poderoso do Python que ajuda a resolver problemas complexos, dividindo-os em subproblemas mais simples. Quando usada corretamente, a recursão leva a um código limpo, conciso e fácil de entender. 

No entanto, é essencial definir casos de base adequados e estar atento à profundidade da recursão para evitar erros comuns. 

Embora a recursão possa, às vezes, ser menos eficiente do que a iteração, ela é uma ferramenta inestimável para resolver determinados tipos de problemas, especialmente aqueles que envolvem dados hierárquicos ou problemas que naturalmente se prestam a soluções recursivas.

Ao compreender a recursão e praticar com exemplos como fatoriais, sequências de Fibonacci e algoritmos de classificação, você estará bem equipado para aproveitar a recursão em seus projetos Python.

Se você estiver interessado em tópicos mais avançados de Python, nos quais poderia implementar a recursão, confira as seguintes trilhas de aprendizagem: Programação Python, Analista de dados em Pythone Cientista de dados associado em Python

Perguntas frequentes sobre recursão em Python

Como os casos de base funcionam na recursão?

Os casos básicos são condições que interrompem a recursão. Eles impedem que a função se chame indefinidamente e fornecem uma solução direta para a forma mais simples do problema.

A recursão pode ser mais eficiente do que a iteração?

Embora a recursão seja geralmente mais elegante e intuitiva para problemas com uma estrutura recursiva natural, a iteração pode ser mais eficiente em termos de memória e mais rápida para tarefas simples e repetitivas.

Quais são os erros comuns na recursão?

Os erros comuns incluem exceder a profundidade máxima de recursão, não ter um caso de base ou ter um caso de base definido incorretamente, o que pode levar à recursão infinita e ao estouro de pilha.

Quando devo usar a recursão em Python?

Use a recursão quando o problema envolver a divisão em subproblemas menores (como a travessia de árvores ou o cálculo de fatoriais) ou quando a solução recursiva for mais intuitiva e mais limpa do que as alternativas iterativas.

Tópicos

Principais cursos de Python

Programa

Data Analyst in Python

0 min
Develop your data analytics skills in Python. Gain the data analyst skills to manipulate, analyze, and visualize data. No coding experience required!
Ver detalhesRight Arrow
Iniciar curso
Ver maisRight Arrow
Relacionado

Tutorial

Tutorial e exemplos de funções e métodos de lista do Python

Saiba mais sobre as funções e os métodos da Lista do Python. Siga exemplos de código para list() e outras funções e métodos Python agora!
Abid Ali Awan's photo

Abid Ali Awan

7 min

Tutorial

Pesquisa binária em Python: Um guia completo para uma pesquisa eficiente

Aprenda a implementar a pesquisa binária em Python usando abordagens iterativas e recursivas e explore o módulo bisect integrado para obter funções de pesquisa binária eficientes e pré-implementadas.
Amberle McKee's photo

Amberle McKee

12 min

Tutorial

Tutorial de funções Python

Um tutorial sobre funções em Python que aborda como escrever funções, como chamá-las e muito mais!
Karlijn Willems's photo

Karlijn Willems

14 min

Tutorial

Programação orientada a objetos em Python (OOP): Tutorial

Aborde os fundamentos da programação orientada a objetos (OOP) em Python: explore classes, objetos, métodos de instância, atributos e muito mais!
Théo Vanderheyden's photo

Théo Vanderheyden

12 min

Tutorial

Função Python Print()

Saiba como você pode aproveitar os recursos de uma simples função Python Print de várias maneiras com a ajuda de exemplos.
Aditya Sharma's photo

Aditya Sharma

10 min

Tutorial

Tutorial de iteradores e geradores Python

Explore a diferença entre Iteradores e Geradores do Python e saiba quais são os melhores para usar em várias situações.
Kurtis Pykes 's photo

Kurtis Pykes

10 min

Ver maisVer mais