Python variable reference return

3

When we define a variable, we are basically naming a memory address, it follows a script that represents my doubt:

class Spam:

    _value = []

    @classmethod
    def value(cls):
        return cls._value

>>> Spam.value()
[]

So far so good, but the problem is that the class method returns a reference to a variable defined up to now as "privada" , now I can do:

>>> var = Spam.value()
>>> var.append(5)
>>> Spam.value()
[5]
>>> var is Spam.value()
True

In some of the codes I'm reading, they avoid returning a reference to the variable itself, and return a copy of it as follows:

class Spam:

    _value = []

    @classmethod
    def value(cls):
        return cls._value.copy()

>>> Spam.value()
[]
>>> var = Spam.value()
>>> var.append(5)
>>> var
[5]
>>> Spam.value()
>>> []
>>> var is Spam.value()
False

Is there any other way to avoid returning the reference in Python?

    
asked by anonymous 12.08.2018 / 05:02

2 answers

0

In python, there are no different values. There is only a single value type , which is "reference" . In python, the variables do not store equal memory addresses in other languages. The variables only keep references, those who use memory are the objects.

What we actually have are names and references . Each name saves a value that is a reference to an object.

When an object has no further reference it is removed from memory and the space it occupied is freed.

For example:

x = 5

After executing the above line, x is a name that has a reference to the object of type int 5

y = x

Now, y is another name that has a reference to the same object as x

x = x + 1

Now we are doing a sum operation, that is, int.__add__(x, 1) that creates and returns a new object of type int , the 6 . x now has a reference to this new int object. The name y continues to refer to the object 5 .

It complicates when using changeable objects as lists:

a = []
b = a
a.append('Teste')

There is only one list, created on the first line of this piece of code. The append() method does not create a new list, it modifies the list it refers to, so you have two names referring to the same object.

If you were passing a reference as in the C language, doing b = 5 would affect a , but it does not happen, because they are not memory addresses, but names that hold references.

  

Is there any other way to avoid returning the reference in Python?

In its first example, return is returning the value associated with the name _value , but this value is a reference to the previously created list:

return cls._value

That is, this form of functioning is part of the language and there is no way to modify it. All values will always be references.

    
13.08.2018 / 18:13
0

What we want is basically to do list_2 = list_1 without list_2 being a reference to list_1, that is, we want to copy only the values.

Another solution besides copy () is to use the deepcopy () function:

from copy import deepcopy

lista_1 = [1,4]
lista_2 = deepcopy(lista_1)
lista_2.append('mudei aqui')

>>> print('lista_1:', lista_1)
lista_1: [1, 4]
>>> print('lista_2:', lista_2)
lista_2: [1, 4, 'mudei aqui']

Another way to copy just the values from a list is:

lista_1 = []
lista_2 = lista_1[:]
lista_2.append('mudei aqui')

>>> print('lista_1:', lista_1)
lista_1: []
>>> print('lista_2:', lista_2)
lista_2: ['mudei aqui']

Using your class, it would look like:

class Spam:

    _value = []

    @classmethod
    def value(cls):
        return cls._value[:]
        #OU return deepcopy(cls._value)

The answer basically comes down to: copying the values (value by value) and not the object. We can even do a function for this (since the lista_1[:] method does not work for arrays), but copy () and deepcopy () already solve ...

def copia_lista(lista):
    lista_copia = []
    for i in range(0, len(lista)):
        lista_copia.append(lista[i])
    return lista_copia

def copia_matriz(matriz):
    matriz_copia = []
    for i in range(0, len(matriz)):
        linha_copia = []
        for j in range(0, len(matriz[i])):
            linha_copia.append(matriz[i][j])
        matriz_copia.append(linha_copia)
    return matriz_copia

class Spam:

    _value = []

    @classmethod
    def value(cls):
        return copia_lista(cls._value)
    
12.08.2018 / 06:05