Este documento descreve a estrutura de classes abstratas para representar tipos numéricos na linguagem Python, conforme definido na PEP 3141. O sistema propõe uma hierarquia de herança onde cada nível representa propriedades matemáticas específicas, permitindo operações consistentes entre diferentes tipos numéricos.
A arquitetura central baseia-se na seguinte cadeia de herança: Numerico :> Complexo :> Real :> Racional :> Integral, onde A :> B indica que A é subclasse de B. Essa estrutura foi inspirada no "numeric tower" da linguagem Scheme.
Estrutura das Classes Abstratas
A classe raiz Numerico serve apenas como marcador para sobrecarga de funções:
class Numerico(metaclass=ABCMeta):
pass
A classe Complexo define operações para números complexos, incluindo métodos abstratos essenciais:
class Complexo(Numerico):
@abstractmethod
def para_complexo(self):
"""Converte para tipo complex nativo."""
raise NotImplementedError
@abstractproperty
def real_parte(self):
"""Componente real do número (deve ser Real)."""
raise NotImplementedError
@abstractproperty
def imaginario_parte(self):
"""Componente imaginário (deve ser Real)."""
raise NotImplementedError
@abstractmethod
def __adicionar__(self, outro):
raise NotImplementedError
# Métodos omitidos para brevidade: __subtrair__, __multiplicar__, etc.
A classe Real estende Complexo adicionando operações específicas para números reais:
class Real(Complexo):
@abstractmethod
def para_float(self):
"""Conversão para tipo float nativo."""
raise NotImplementedError
@abstractmethod
def truncar(self):
"""Retorna parte inteira sem arredondamento."""
raise NotImplementedError
@abstractmethod
def arredondar(self, casas: Integral = None):
"""Arredonda para casas decimais especificadas."""
raise NotImplementedError
A hierarquia continua com Racional para frações e Integral para números inteiros:
class Racional(Real):
@abstractproperty
def numerador(self):
raise NotImplementedError
@abstractproperty
def denominador(self):
raise NotImplementedError
class Integral(Racional):
@abstractmethod
def para_inteiro(self):
raise NotImplementedError
def operacao_bitwise_esquerda(self, outro):
return self.para_inteiro() << outro.para_inteiro()
Implementação de Operações
Para operações mistas entre tipos diferentes, a implementação deve seguir padrões específicos. Exemplo de adição em uma subclasse de Integral:
class MeuInteiro(Integral):
def __adicionar__(self, outro):
if isinstance(outro, MeuInteiro):
return calcular_soma(self, outro)
elif isinstance(outro, TipoEspecial):
return calcular_soma_especial(self, outro)
return NotImplemented
def __r_adicionar__(self, outro):
if isinstance(outro, Integral):
return outro.para_inteiro() + self.para_inteiro()
elif isinstance(outro, Real):
return outro.para_float() + float(self.para_inteiro())
return NotImplemented
Considerações para Desenvolvedores
Ao implementar novos tipos numéricos:
- Garanta que valores equivalentes tenham o mesmo hash
- Utilize
register()para adicionar classes intermediárias - Respeite a ordem de conversão: Entegral → Real → Complexo
Operações como trunc(), floor() e ceil() exigem implementações específicas em subclasses de Real, enquanto operações bitwise são exclusivas de Integral. O sistema permite que bibliotecas como NumPy definam tipos numéricos customizados compatíveis com a hierarquia padrão.