Olá, Anderson. Como vai?
Parabéns pela excelente estruturação do seu código! Você aplicou conceitos avançados de Orientação a Objetos (OO) em Python de forma muito organizada, dividindo as classes em arquivos separados e montando uma visualização final alinhada com o método ljust.
A utilização de classes abstratas com o módulo abc (ABC e @abstractmethod) é uma excelente prática quando queremos criar um contrato para as nossas classes filhas, garantindo que toda classe que herde de Veiculo seja obrigada a implementar o método ligar.
Para agregar ainda mais valor ao seu projeto e trazer boas práticas do ecossistema Python, destaco alguns pontos de melhoria e refinamento técnico:
1. Ajuste na assinatura do método abstrato
No arquivo veiculo.py, dentro da classe Veiculo, o método abstrato ligar() foi definido sem o parâmetro self. Em Python, todo método de instância precisa receber o self explicitamente como primeiro parâmetro. Sem ele, você terá um erro de assinatura ao tentar usar o método a partir da herança. O correto seria:
@abstractmethod
def ligar(self):
pass
2. Encapsulamento e Boas Práticas (Acessando Atributos Protegidos)
Ao definir os atributos com um underline no início (como self._marca, self._modelo e self._cor), você indicou na convenção do Python que esses atributos são protegidos (internos da classe). No entanto, no arquivo main.py, você os acessou diretamente: carro1._marca.
Embora o Python permita isso, a boa prática da Orientação a Objetos sugere que utilizemos o decorador @property para criar métodos de leitura (getters) seguros, ou que criemos um método especial de exibição dentro da própria classe (como o método mágico __str__).
Código Otimizado e Refatorado:
Veja como o seu projeto ganharia ainda mais robustez aplicando as propriedades e o método __str__ para simplificar o seu main.py:
Arquivo veiculo.py:
from abc import ABC, abstractmethod
class Veiculo(ABC):
def __init__(self, marca, modelo):
self._marca = marca
self._modelo = modelo
@property
def marca(self):
return self._marca
@property
def modelo(self):
return self._modelo
@abstractmethod
def ligar(self):
pass
Arquivo carro.py:
from veiculo import Veiculo
class Carro(Veiculo):
def __init__(self, marca, modelo, cor):
super().__init__(marca, modelo)
self._cor = cor
@property
def cor(self):
return self._cor
def ligar(self):
print(f'O carro {self._modelo} está ligado.')
def __str__(self):
return f'{self._marca.ljust(15)} | {self._modelo.ljust(15)} | {self._cor}'
Arquivo main.py:
from carro import Carro
carro1 = Carro('Toyota', 'Corolla', 'Preto')
carro2 = Carro('Audi', 'R8', 'Vermelho')
carro3 = Carro('BMW', 'X6', 'Branca')
print(f"{'Marca'.ljust(15)} | {'Modelo'.ljust(15)} | Cor")
print(carro1)
print(carro2)
print(carro3)
Note como o uso do método especial __str__ dentro de carro.py limpou completamente o arquivo main.py. Agora, sempre que você der um print(carro1), o Python já saberá exatamente como formatar e alinhar o texto na tela de forma elegante. Além disso, as propriedades nos permitem acessar os dados de forma limpa usando apenas carro1.marca se precisarmos futuramente.
Você demonstrou excelente domínio sobre o uso de super().__init__ para herança de propriedades! Continue evoluindo na arquitetura de códigos em Python.
Espero que possa ter lhe ajudado!