Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Composição em Python. Como chamar a classe da composição no Construtor da outra classe.

Estou começão a programar em Python e estou com uma dúvida de como usar usar a composição de classes do O.O. no Python. Exemplo quero criar uma classe Cliente que possui os seguintes atributos ( nome, data de nascimento, CPF, endereço) porém o endereço quero modelar também como uma classe contendo os seguintes atributos (rua, numero, cep, complemento). Ai que está minha dúvida na linguagem Java posso fazer a composição já no construtor da classe. Isto é possível em Python? Eu fiz escrevi assim:

# Classe Endereco
class Endereco():
    def __init__(self, rua, numero, cep, complemento = 'casa'):
        self.rua = rua
        self.cep = cep
        self.__numero = self.add_numero(numero)
        self.complemento = complemento

    def add_numero(self, numero):
        if(numero.isnumeric()):
            self.numero = numero
        else:
            self.numero = 0

    def __str__(self):
        return f'Rua: {self.rua} - n.o: {self.numero} - Cpl: {self.complemento} - CEP: {self.cep} '

# Classe Cliente:  cliente que é representado através de seu nome, endereço, data nascimento, cpf e tipo de cliente.
class Cliente():
    def __init__(self, nome, data_nascimento, cpf, tipo_cliente = 'Normal'):
        self._nome = nome
        self._data_nascimento = data_nascimento
        self._cpf = cpf
        self.tipo_cliente = tipo_cliente
        self.endereco = []

    def addEndereco(self, rua, cep, numero, complemento):
        self.endereco.append(Endereco(rua, cep, numero, complemento))

##################

cliente1 = Cliente('Heitor Batistela Zunta', '26/11/1983', '996828421-15')
cliente1.addEndereco('Rua Bangu', "121", "791121-210", 'casa' )

for endereco in cliente1.endereco:
    print(endereco)

Gostaria de obrigar o construtor a receber um endereço para criar o objeto cliente. Como faria isto?

2 respostas
solução!

Olá, Heitor.

Você quer forçar que o parâmetro endereco (na classe Cliente) seja uma variável do tipo Endereco?

Se for isso, o Python não dá suporte. Pelo que li aqui e aqui, o Python somente permite anotações (annotations). As anotações são um recurso que permite adicionar metadados arbitrários aos parâmetros de função e retornar valor, mas isso não força o tipo de variável (pelo menos não até a versão atual do Python). O máximo que se pode fazer é adicionar plugins as IDEs pra que chequem isso. Pode encontrar como fazer isso aqui (na parte de Running the Type Checker).

Caso você queira apenas fazer com que o parâmetro endereco (na classe Cliente) receba um objeto do tipo Endereco, mesmo que vazio. Você pode realizar algumas mudanças nas classes Endereco e Cliente. Fiz algumas modificações que permitem isso, só não sei o quão "pytônico" isso é.

A primeira coisa a se fazer é permitir que a classe Endereco possa ser instanciada usando endereco = Endereco(). Você pode fazer isso através de *args e **kargs (material) ou só colocando um valor padrão para cada argumento (bem mais fácil, mas meio gambiarra). Depois disso, basta colocar o valor padrão da variável endereco como Endereco(). Pra isso, você também terá que modificar a chamada do __init__ da classe Cliente.

Fiz essas modificações aqui e funcionou perfeitamente.

Também modifiquei a ordem dos parâmetros (coloquei o endereco antes da variável tipo_cliente), pois o python não aceita que se coloque argumentos com valores padrão antes de argumentos livres.

# Classe Endereco
class Endereco():
    def __init__(self, rua='', cep='', numero='', complemento='casa'):
        self.rua = rua
        self.cep = cep
        self.__numero = self.add_numero(numero)
        self.complemento = complemento

    def add_numero(self, numero):
        if(numero.isnumeric()):
            self.numero = numero
        else:
            self.numero = 0

    def __str__(self):
        return f'Rua: {self.rua} - n.o: {self.numero} - Cpl: {self.complemento} - CEP: {self.cep} '


# Classe Cliente:  cliente que é representado através de seu nome, endereço,
# data nascimento, cpf e tipo de cliente.
class Cliente():
    def __init__(self, nome, data_nascimento, cpf, tipo_cliente='Normal', endereco=Endereco()):
        self._nome = nome
        self._data_nascimento = data_nascimento
        self._cpf = cpf
        self.tipo_cliente = tipo_cliente
        self.endereco = endereco

    def addEndereco(self, rua, cep, numero, complemento):
        self.endereco.append(Endereco(rua, cep, numero, complemento))

##################


cliente1 = Cliente('Heitor Batistela Zunta',
                   '26/11/1983',
                   '996828421-15')

cliente2 = Cliente('Heitor Batistela Zunta',
                   '26/11/1983',
                   '996828421-15',
                   endereco=Endereco('Rua Bangu', "121", "791121-210", 'casa'))

print(cliente1.endereco)
print(cliente2.endereco)

Era isso que você queria?

Espero ter ajudado.

P.S. removi as linhas que tinham o for, pois objetos do tipo Endereco não são iteráveis.

Foi certeiro na dúvida Madson! Era esta a minha dúvida. Obrigado!