Reference and Parameter in Python

Asked

Viewed 896 times

1

I have a Python class that has a function that returns me a triple (3 information together) and I wanted to create 4 different objects because I need 4 different triples. The question is that the values accumulate and the 4th object has the information of him and the other 3 previous ones. Does anyone know why? That is, each time I call the function, the list (overall in class) is not overwritten.

class Anel():

    nomeResiduo = ""
    numCadeias = 1
    centroide = []

    def preencheAnel(self, residuo):

        i=0
        aux = residuo[0][4]

        while i < (len(residuo)):
            if ((i+1) < len(residuo)):
                if(aux != residuo[i+1][4]):
                    self.numCadeias += 1
                aux = residuo[i+1][4]
            i=i+1

        i = 0
        atomosPorCadeia = len(residuo)/self.numCadeias

        while i < self.numCadeias:
            centroide.append(Anel().calculaCentroide(residuo, self.numCadeias, i))
            i += 1

        self.nomeResiduo = residuo[0][2]

        return (self.nomeResiduo, self.numCadeias, centroide)
  • If you set the property in the class outside the instance initializer, it will be a property of the class and not of the object, so it makes no sense to overwrite each instance. To get around this, you can define it within the __init__, but if possible, edit your question and put the source code, then we can help with greater accuracy.

  • Without seeing your code, there’s no way to explain what’s going on.

  • 1

    But you’re probably confusing class attribute with instance attribute - or using a list as the default method parameter.

  • I think it might actually be that, because when I declared the list as a local variable of a function rather than a global variable of the class, it worked normal.

1 answer

3


As discussed in the comments, you confused class attribute with instance attribute. When defining the form attribute:

class Foo:
    attribute = ["Hello"]

    def add(self, value):
        self.attribute.append(value)

We call it a class attribute and it will be common to all instances of it. For example, consider the two objects:

>>> foo1 = Foo()
>>> foo2 = Foo()

If we change the value of the attribute of one object, the other will be changed as well, because the attribute is of the class.

>>> foo1.add("Stack Overflow")
>>> print(foo2.attribute)
['Hello', 'Stack Overflow']

To circumvent this, you can define the attribute as an instance attribute by defining it within the instance initializer:

class Foo:
    def __init__(self):
        self.attribute = ["Hello"]
    ...

Thus, by changing the value of one object, the other will not be affected:

>>> foo1.add("Stack Overflow")
>>> print(foo2.attribute)
['Hello']

In your case, the attribute in question is centroide then you can do:

class Anel:

    def __init__(self):
        self.nomeResiduo = ""
        self.numCadeias  = 1
        self.centroide   = []
    ...

Or use variables as locations to the method, if there is no need for them to be instance attributes.

It is worth noting that this happens only with changeable types, as the list, because to change it is not necessary an assignment.

When the type used is immutable you will not have this problem:

class Foo:
    number = 1

Thus:

>>> foo1 = Foo()
>>> foo2 = Foo()
>>> foo1.number = 2
>>> foo2.number
1

That’s because when you do foo1.number = 2 you are not modifying the value, but creating a new instance of int and referencing it in an instance attribute. Yes, it becomes an instance attribute. Python stores attributes internally in a dictionary; class attributes are stored in a class dictionary (Foo.__dict__) while the instance attributes are stored in an instance dictionary (foo1.__dict__). When you access an attribute, Python will internally search the instance dictionary and, if it does not find the attribute definition, search the class dictionary, following the MRO definitions.

When you make a new one attribution in the instance you will define a instance attribute, preference to the class attribute. This applies even to mutable types:

class Foo:
    numbers = [100]

Thus:

>>> foo1 = Foo()
>>> foo2 = Foo()
>>> foo1.numbers = [100, 200]
>>> foo2.numbers
[100]

'Cause in this case, you’re not modifying the class attribute, but rather defining an instance attribute in foo1 with a list completely different from the one defined as class attribute; so much so that you can still do foo1.__class__.numbers and you’ll see the list [100] remains there as unaltered class attribute.

  • Wow, thank you so much. Solved here and also understood what I did wrong.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.