0
respostas

[Sugestão] Desafio: refatorando nossa classe - inclusão do método __add__ para juntar os dados da empresa A e da empresa B

Minha solução para o desafio

Na solução do professor, o método join() recebe dois objetos da classe Dados, acessa os dados internos de cada um e retorna um novo objeto Dados, usando o tipo especial 'list' para representar dados que já estão em memória.

Na minha implementação, segui uma abordagem um pouco diferente. Em vez de criar um método join(), optei por implementar o método especial add, que permite combinar dois objetos Dados usando o operador +.

Assim, em vez de fazer algo como:
dados_fusao = Dados.join(dados_empresaA, dados_empresaB)
eu consigo fazer:
dados_fusao = dados_empresaA + dados_empresaB

A ideia foi deixar a operação mais natural: se tenho dois conjuntos de dados, posso “somá-los” para gerar um novo conjunto combinado.

Encapsulamento aplicado
Também procurei aplicar o conceito de encapsulamento. Para isso, deixei como métodos internos da classe aqueles que não fazem sentido serem chamados diretamente pelo usuário:

__inicializa_atributos
__leitura_json
__leitura_csv
__leitura_dados

Esses métodos fazem parte do funcionamento interno da classe. Ou seja, o usuário da classe não precisa saber exatamente como a leitura do CSV ou do JSON acontece. Ele só precisa instanciar o objeto:

dados_empresaA = Dados('data_raw/dados_empresaA.json')
dados_empresaB = Dados('data_raw/dados_empresaB.csv')

Os atributos principais também foram protegidos com _, como:

self._dados
self._qtd_linhas
self._nome_colunas
self._path
self._tipo_dados

E o acesso a alguns deles foi feito por meio de @property, por exemplo:

@property
def dados(self):
    return self._dados

Com isso, consigo acessar:

dados_empresaA.dados
dados_empresaA.qtd_linhas
dados_empresaA.nome_colunas

mas mantendo maior controle interno sobre como esses valores são calculados ou atualizados.

Diferença em relação à solução com classmethod
Na proposta do professor, a refatoração sugerida usa @classmethod para criar objetos a partir de arquivos CSV ou JSON. Essa abordagem deixa o init mais simples, porque ele passa a receber diretamente os dados já lidos.

No meu caso, mantive o init recebendo o caminho do arquivo e deixei a própria classe identificar se o arquivo é .json ou .csv. Então, para conseguir criar um novo objeto a partir da soma de dois objetos existentes, usei o método add.

O trecho principal foi este:

def __add__(self, other):
    if not isinstance(other, Dados):
        raise ValueError("Apenas objetos do tipo Dados podem ser somados.")

    dados_combinados = self.dados + other.dados

    nova_instancia = Dados.__new__(Dados)
    nova_instancia._dados = dados_combinados
    nova_instancia._qtd_linhas = len(dados_combinados)
    nova_instancia._nome_colunas = list(set(self.nome_colunas) | set(other.nome_colunas))

    return nova_instancia

Usei Dados.__new__(Dados) porque o meu __init__ espera receber um caminho de arquivo. Como, nesse caso, os dados combinados já estão em memória, eu precisava criar uma nova instância sem passar novamente pela leitura de arquivo.

Observação importante
Essa solução funciona, mas exige cuidado: como __new__ cria o objeto sem chamar o __init__, alguns atributos que normalmente seriam inicializados no construtor precisam ser definidos manualmente.

Por exemplo, seria interessante completar o método __add__ assim:

def __add__(self, other):
    if not isinstance(other, Dados):
        raise TypeError("Apenas objetos do tipo Dados podem ser somados.")

    dados_combinados = self.dados + other.dados

    nova_instancia = Dados.__new__(Dados)
    nova_instancia._path = "dados em memória"
    nova_instancia._tipo_dados = "memória"
    nova_instancia._dados = dados_combinados
    nova_instancia._qtd_linhas = len(dados_combinados)
    nova_instancia._nome_colunas = list(set(self.nome_colunas) | set(other.nome_colunas))

    return nova_instancia

Assim, o novo objeto fica mais consistente internamente.

Minha solução é mais alinhada com __add__ e explora um recurso especial do Python que é a sobrecarga de operadores. No meu entendimento, o uso de add deixa a união dos dados mais expressiva, porque representa a combinação de dois objetos Dados como uma soma entre eles.