6

I need to have several objects that each one has an individual array. I have written this code:

    read_values = list()
    for read_unit in read_units:
        read_value = ReadValues.objects.all().filter(ReadID=read_unit.ReadID)

        element = TempObjectForReadValues()
        for read_element in read_value:
            element.read_elements[read_element.Code] = read_element.ReadValue
        read_values.append(element)
        print(element.read_elements)

    print('  ')
    for test_element in read_values:
        print(test_element.read_elements)

And this is how I defined the class:

    class TempObjectForReadValues():
        read_elements = [None] * 10

The result is:

[None, None, 16.0, None, 189.0, 345.0, None, None, None, None]
[None, None, 16.0, 43.0, 876.0, 345.0, None, None, None, None]

[None, None, 16.0, 43.0, 876.0, 345.0, None, None, None, None]
[None, None, 16.0, 43.0, 876.0, 345.0, None, None, None, None]

That means the data are overwritten on the previous ones. Also if I do not assign anything to the array in new object, it holds the results from previous one. :(

How can I fix it?

Happy Ahmad
  • 1,072
  • 2
  • 14
  • 33

1 Answers1

4

Python syntax, unlike Java and C++, does not specify instance attributes on the class body. Instead, any attributes specified in the class body are class attributes. That means your read_elements array is essentially a singleton shared across all instances of your TempObjectForReadValues class.

To fix that, just create whatever attributes are intended as instance attributes inside the initialization code for your objects (i.e. the __init__ method):

class TempObjectForReadValues:
    def __init__(self):
        self.read_elements = [None] * 10

Now, note that for more sophisticated class hierarchies and specific needs, Python does implement a mechanism called "descriptor protocol" that allows specialized objects assigned as class attributes to manage the reading/writting and deletion of attributes with the same names on each instance.

One of the most common uses is the property (which is even a built-in function in the Language) - it just takes from 1 to 3 callable parameters, each one to be an getter/setter/deleter of an attribute. This mechanism can also be used for ORM strategies, interface implementations, and a lot of other things.

In your case, you could do:

class TempObjectForReadValues:
    read_elements = property(lambda self: self.__dict__.setdefault("_read_elements", [None] * 10))

(this is a hackish implementation to keep the code in a single line, and is equivalent to:

class TempObjectForReadValues:
    @property
    def read_elements(self):
        if not hasattr(self, "_read_elements"):
            self._read_elements = [None] * 10
        return self._read_elements

)

jsbueno
  • 99,910
  • 10
  • 151
  • 209