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

Dúvida sobre o funcionamento de listas e suas cópias

Eu n sei se vou saber explicar minha dúvida, mas vou tentar mesmo assim.

Bom, no código o instrutor falou que precisamos criar uma cópia da lista para poder evitar que o usuário dê um append na lista de lances diretamente. Até aí eu entendi, pois cria-se uma nova ID com a cópia que referencia outro objeto na memória. Mas a Classe AVALIADOR() utiliza justamente a property lances() que referencia a cópia da lista de lances para poder fazer sua avaliação. Pelos testes quer eu fiz, quando vc usa uma cópia da lista original, nem a cópia da lista original e nem a lista original recebem os valores do append que vc tenta fazer quando está usando a orientação a objeto. Eu gostaria de saber prque nem a copia nem a lista original recebem os valores quando vc usa o append e prque elas so recebem os valores quando vc usa a propriedade que vc criou.

N sei se consegui explicar minha dúvida direito, me desculpa se n fui claro. Vou deixar um teste que eu fiz aqui

class Lance:

    def __init__(self, nome,  valor):
        self.nome = nome
        self.valor = valor


class Leilao:

    def __init__(self, descricao):
        self.descricao = descricao
        self.__lances = []

    def propoe(self, lance: Lance):
        self.__lances.append(lance)

    @property
    def lista_verdadeira(self):
        return self.__lances

    @property
    def lances(self):
        return self.__lances[:]


#Criando leilao
leilao = Leilao('celular')

#Criando lances
lance = Lance('João', 200)
lance2 = Lance('Luma', 300)

#Antes do propoe
leilao.lances.append(lance)
leilao.lances.append(lance2)
print('Antes do propoe')
print(leilao.lances)
print(leilao.lista_verdadeira)
for lance in leilao.lista_verdadeira:
    print(lance.valor)

#Depois do propoe
leilao.propoe(lance)
leilao.propoe(lance2)
print('Depois do propoe')
print(leilao.lances)
print(leilao.lista_verdadeira)

for lance in leilao.lista_verdadeira:
    print(f'lance {lance.valor} de {lance.nome}')

Resultado:

Antes do propoe
[]
[]
Depois do propoe
[<__main__.Lance object at 0x000002A932ABF908>, <__main__.Lance object at 0x000002A932ABF988>]
[<__main__.Lance object at 0x000002A932ABF908>, <__main__.Lance object at 0x000002A932ABF988>]
lance 200 de João
lance 300 de Luma
4 respostas

A diferença entre as duas etapas, o método propoe() e a property "lances", é que no primeiro você acessa diretamente o OBJETO LISTA e usa o append() para adicionar um item nesse objeto. O que seria o mesmo de pegar diretamente um objeto lista e usar append():

lista_exemplo = []  #objeto
lista_exemplo.append("Valor")  #objeto + método

No segundo, o property, você está retornando na função a matriz do objeto, seus valores (que não existe algum valor até o momento), e não o OBJETO lista, por isso o append() não "funciona" e a lista continua vazia... Se você remover o slice ([:]) vai ter outro resultado de saída, mas eu recomendo comentar a segunda parte ("após o propoe") pois vai rolar uma duplicata na lista e vai ficar uma coisa bem bagunçada rs

lista_exemplo = []  #lista vazia
...

def lances():
    return lista_exemplo[:]  #retorna todo conteúdo da lista, ou seja, nada até agora

lances.append("valor")  #não vai fazer nada pois o valor da lista não é um objeto lista

Então a cópia de uma lista dentro de um property faz referencia somente aos valores dentro da lista original? Por isso que vc n pode adicionar nada nessa cópia? Isso somente na programação orientada a objeto certo? Pq nesse trecho de código aqui (fora da programação orientada a objeto) está funcionando um append na cópia da lista

lista = []
lista_copia = lista[:]
lista_copia.append('Oi')
print(lista)
print(lista_copia)

Resposta:

[]
['Oi']
solução!

O problema ocorre não é bem pela lista, mas pelo slice, eu fiz alguns testes mas foi legal pra que eu veja que preciso aprender mais sobre o debugger da IDE, ou eu realmente estou vendo a coisa certa e estou procurando problema que não existe haha.

Bom, seguindo meus testes:

class Teste:
    __lista = ['exemplo']

    @property
    def lista_property(self):
        return self.__lista[:]  #<-- Slice, pra mim aqui está sendo retornado os valores da lista, não o objeto


teste = Teste()

lista_copia = teste.lista_property  #copiando a lista da classe com 1 item
print(lista_copia)  #mostrando na tela

teste.lista_property.append('Oiii')  #tentando adicionar um item diretamente
print(teste.lista_property)  #ficando frustrado por não acontecer nada

Usando o slice lá acima, o append não funciona, e eu ainda não sei dizer o porque, talvez eu deva ler um pouco mais sobre o slice pois claramente tem algo que eu não peguei ou esqueci que está causando isso, removendo ele, tudo flui normalmente.

Ou como citei anteriormente, quando usamos o slice ali em cima, nós retornamos o conteúdo da lista, não o objeto lista, o conteúdo da lista não tem um método append() por isso não faz nada. Já o objeto lista tem o método append(), por isso funciona, mas para isso ocorrer temos que retornar o objeto lista na função, logo temos que remover o slice:

class Teste:
    __lista = ['exemplo']

    @property
    def lista_property(self):
        return self.__lista  #SLICE removido, agora o método retorna o OBJETO LIST


teste = Teste()

lista_copia = teste.lista_property
print(lista_copia)

teste.lista_property.append('Oiii')
print(teste.lista_property)

Muito Obg Thiago! Agr entendi!