Frações aparecem em receitas, proporções, escalas, música, probabilidades, conversões e algoritmos matemáticos. Usar float para representar 1/3 ou 2/7 produz aproximações, enquanto converter tudo para Decimal nem sempre resolve números periódicos. O módulo fractions no Python oferece a classe Fraction, que armazena numerador e denominador como inteiros e mantém cálculos racionais exatos.
Neste guia, você aprenderá a criar frações de inteiros, strings, Decimal e floats, simplificar valores, recuperar aproximações com limit_denominator(), formatar resultados e escolher entre Fraction, Decimal e float. O conteúdo complementa nossos artigos sobre float em Python, Decimal, inteiros, tipos de dados e formatação com f-strings.
O que é um número racional
Um número racional pode ser escrito como a razão entre dois inteiros, com denominador diferente de zero. Exemplos incluem 1/2, -7/3, 5 e 0.125. A classe Fraction conserva essa estrutura:
from fractions import Fraction
metade = Fraction(1, 2)
terco = Fraction(1, 3)
print(metade)
print(terco)As instâncias são imutáveis e hashable, portanto podem ser usadas como chaves de dicionário e elementos de conjuntos.
Normalização automática
O construtor reduz a fração aos menores termos e mantém o denominador positivo.
from fractions import Fraction
print(Fraction(16, -10)) # -8/5
print(Fraction(20, 30)) # 2/3O módulo usa máximo divisor comum para normalização. Não é necessário simplificar manualmente depois de cada operação.
Criando Fraction de strings
Strings são uma forma segura de preservar a intenção textual.
from fractions import Fraction
print(Fraction("3/7"))
print(Fraction(" -3 / 7 "))
print(Fraction("0.125"))
print(Fraction("7e-6"))Desde o Python 3.12, espaços em torno da barra são aceitos. Valores decimais finitos viram razões exatas, como 0.125 = 1/8.
Construção a partir de float
Um float é convertido para sua representação binária exata, não necessariamente para a fração decimal que você imaginou.
from fractions import Fraction
print(Fraction(1.1))
# 2476979795053773/2251799813685248A causa é a mesma discutida na documentação oficial sobre ponto flutuante: 1,1 não possui representação binária finita. Para representar exatamente onze décimos, use Fraction("1.1") ou Fraction(11, 10).
Fraction a partir de Decimal
Um Decimal finito é convertido exatamente:
from decimal import Decimal
from fractions import Fraction
valor = Fraction(Decimal("1.1"))
print(valor) # 11/10Essa conversão é útil quando uma entrada foi validada como decimal, mas o algoritmo precisa trabalhar com uma razão exata.
from_number() no Python 3.14
O Python 3.14 adicionou Fraction.from_number(). Ele aceita inteiros, racionais, floats, Decimal e objetos com as_integer_ratio(), mas não strings.
from fractions import Fraction
print(Fraction.from_number(5))
print(Fraction.from_number(2.25))A conversão de float continua refletindo o valor binário exato. A nova API apenas torna explícita a expectativa de receber um objeto numérico.
Operações aritméticas exatas
from fractions import Fraction
a = Fraction(1, 3)
b = Fraction(1, 6)
print(a + b) # 1/2
print(a - b) # 1/6
print(a * b) # 1/18
print(a / b) # 2Os resultados permanecem normalizados. Potenciação com expoente inteiro também funciona, inclusive com expoentes negativos quando a base não é zero.
Numerator e denominator
Os atributos de leitura expõem os componentes na forma reduzida:
valor = Fraction(42, 56)
print(valor.numerator) # 3
print(valor.denominator) # 4O denominador é sempre positivo. O sinal fica no numerador.
Recuperando uma fração legível de um float
limit_denominator() encontra a aproximação mais próxima cujo denominador não ultrapassa um limite.
from fractions import Fraction
aproximacao = Fraction(1.1).limit_denominator()
print(aproximacao) # 11/10A documentação oficial de fractions também mostra a aproximação 355/113 para pi quando o denominador máximo é 1000.
from fractions import Fraction
pi_aprox = Fraction("3.141592653589793").limit_denominator(1000)
print(pi_aprox) # 355/113Escolhendo max_denominator
O limite deve refletir o problema. Em uma receita culinária, denominadores até 16 podem ser suficientes. Em uma aproximação científica, talvez sejam necessários milhares.
valor = Fraction("0.3332")
print(valor.limit_denominator(10))
print(valor.limit_denominator(1000))Um limite alto melhora a aproximação, mas pode produzir razões difíceis de interpretar. Defina a tolerância e valide o erro resultante.
Verificando se a fração é inteira
Desde o Python 3.12, is_integer() indica se o denominador reduzido é 1.
print(Fraction(6, 3).is_integer()) # True
print(Fraction(7, 3).is_integer()) # FalseVocê também pode converter com int(), mas essa conversão trunca em direção a zero. Não use como teste de integralidade.
floor, ceil e round
Fraction integra-se às funções de arredondamento:
import math
from fractions import Fraction
valor = Fraction(7, 3)
print(math.floor(valor))
print(math.ceil(valor))
print(round(valor, 2))round() usa empates para o par. Quando ndigits é fornecido, o resultado continua sendo Fraction.
Formatação com f-strings
Versões recentes do Python ampliaram a formatação. Desde 3.12, tipos de apresentação como f, e, g e porcentagem estão disponíveis.
from fractions import Fraction
valor = Fraction(1, 7)
print(f"{valor:.6f}")
print(f"{valor:.2%}")Desde o Python 3.13, formatação sem tipo também suporta alinhamento, sinal, largura e agrupamento.
print(f"{Fraction(103993, 33102):_}")
print(f"{Fraction(3, 1):#}")A flag # força a exibição do denominador, inclusive em valores inteiros.
Comparações e ordenação
Frações podem ser comparadas com inteiros, floats e Decimal, embora comparações com float reflitam sua aproximação binária.
valores = [Fraction(2, 3), Fraction(1, 2), Fraction(3, 4)]
print(sorted(valores))Para regras exatas, normalize os tipos antes da comparação.
Frações em receitas e proporções
from fractions import Fraction
receita_base = Fraction(3, 4)
fator = Fraction(5, 2)
quantidade = receita_base * fator
print(quantidade) # 15/8Você pode separar a parte inteira e a fração restante para exibição amigável.
inteiro = quantidade.numerator // quantidade.denominator
resto = quantidade - inteiro
print(inteiro, resto)Probabilidades exatas
Frações são úteis em espaços amostrais pequenos:
favoraveis = 6
possiveis = 36
probabilidade = Fraction(favoraveis, possiveis)
print(probabilidade) # 1/6Em modelos grandes, numeradores e denominadores podem crescer rapidamente. Para estatística numérica em escala, float e bibliotecas vetorizadas podem ser mais adequados.
Conversões de unidades
Fatores racionais evitam erros acumulados:
polegadas_por_pe = Fraction(12, 1)
pes = Fraction(5, 2)
polegadas = pes * polegadas_por_pe
print(polegadas) # 30Documente a unidade de cada valor. Exatidão numérica não impede misturar metros e centímetros incorretamente.
Crescimento de numerador e denominador
Operações repetidas podem criar inteiros enormes. A normalização reduz fatores comuns, mas não limita a magnitude.
valor = Fraction(1, 1)
for n in range(2, 50):
valor += Fraction(1, n)
print(len(str(valor.numerator)))Esse custo pode tornar Fraction mais lento e consumir memória. Em algoritmos aproximativos, limite o denominador em pontos controlados ou use outro tipo numérico.
Fraction versus Decimal
Use Fraction quando o valor é naturalmente uma razão e precisa permanecer exato, como 1/3, escalas ou probabilidades combinatórias. Use Decimal quando o domínio trabalha com casas decimais, dinheiro e regras de arredondamento.
Decimal representa 0.1 exatamente, mas 1/3 precisa ser arredondado conforme o contexto. Fraction representa 1/3 exatamente, mas 0.10 é reduzido para 1/10 e não conserva zeros significativos.
Fraction versus float
Float é muito mais rápido e integrado a NumPy, gráficos e bibliotecas científicas. Fraction é melhor para exatidão simbólica em volumes moderados.
Não converta para float no meio de um cálculo exato e depois volte esperando recuperar a razão original. Se a conversão for necessária para uma biblioteca, deixe-a na borda e documente a tolerância.
Serialização
JSON não suporta Fraction nativamente. Uma representação explícita evita ambiguidade:
registro = {
"numerator": valor.numerator,
"denominator": valor.denominator,
}Outra opção é enviar a string "3/4", desde que o contrato da API descreva o formato. Não envie apenas um float quando a exatidão precisa sobreviver.
Validação de entrada
Capture ValueError para strings inválidas e ZeroDivisionError para denominador zero.
from fractions import Fraction
def ler_fracao(texto: str) -> Fraction:
try:
return Fraction(texto)
except (ValueError, ZeroDivisionError) as erro:
raise ValueError("Fração inválida") from erroImponha limites de tamanho em entrada não confiável. Inteiros com milhões de dígitos podem consumir recursos excessivos.
Testando cálculos racionais
assert Fraction(1, 3) + Fraction(1, 6) == Fraction(1, 2)
assert Fraction("0.125") == Fraction(1, 8)
assert Fraction(1.1).limit_denominator() == Fraction(11, 10)Teste também sinais, denominador zero, parsing, formatação e limites de aproximação.
Erros frequentes
- Criar
Fraction(1.1)esperando 11/10. - Usar denominadores ilimitados em dados não confiáveis.
- Escolher Fraction para dinheiro e perder a escala de centavos.
- Converter para float cedo demais.
- Interpretar
int(fracao)como arredondamento. - Usar um
max_denominatorsem medir o erro. - Serializar apenas a aproximação decimal.
- Ignorar o crescimento dos inteiros.
Boas práticas
- Use inteiros ou strings para construção exata.
- Prefira Decimal quando a escala decimal faz parte do contrato.
- Defina limites de denominador conforme o domínio.
- Mantenha Fraction dentro do núcleo exato do cálculo.
- Valide entradas e tamanhos.
- Serialize numerador e denominador explicitamente.
- Meça desempenho em loops grandes.
- Teste aproximações e casos negativos.
Conclusão
O módulo fractions no Python fornece aritmética racional exata com uma API integrada ao restante da linguagem. A classe Fraction normaliza automaticamente numerador e denominador, aceita várias formas de entrada, oferece aproximações controladas e suporta formatação moderna.
A escolha depende da natureza do problema. Frações preservam razões como 1/3; Decimal preserva valores decimais e regras monetárias; float privilegia desempenho e integração numérica. Quando o tipo representa corretamente o domínio, o código evita aproximações desnecessárias e produz resultados mais claros, verificáveis e fáceis de explicar.







