0

I'm setting up a home sensor network and I have multiple "nodes" (Arduino locations) and each node has several datapoints to report. So I'm storing all my nodes (node objects) in a list and each node object has a list of datapoint objects. My problem is that I can't seem to assign datapoints to individual nodes and they are instead assigned to all nodes in the node list.

class datapoint:
    name = ""
    node_number = 0
    node_array_index = 0
    active = False
    log_next = False
    
    
    def __init__(self, name):
        self.name = name
        
class node:
    
    address = [0]*8
    name = " "
    message_now = False
    datapoints = []
    
    def __init__(self, name ):
        self.name = name
    
node_list = []
node_list.append(node("Garden")) 
node_list.append(node("Kitchen"))   

node_list[0].datapoints.append(datapoint("Humidity"))
node_list[1].datapoints.append(datapoint("Temperature"))

for i in range(0,len(node_list[1].datapoints)):
    print(node_list[1].datapoints[i].name)

This returns

Humidity
Temperature

I would have expected this to return Temperature because only Temperature was assigned to node_list[1].datapoints. If I try creating objects first and appending them to the list I get the same result.

Thanks for any help.

  • 2
    The variables are class-bound while they should be bound to an instance. You should first work through the [Python tutorial](https://docs.python.org/3/tutorial/) or another suitable tutorial if not done yet. – Michael Butscher May 07 '23 at 18:18
  • 2
    @MichaelButscher there is actually [a particular section](https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables) explaining the difference (and moreover it has exact same problem demonstration) – sudden_appearance May 07 '23 at 18:19
  • 2
    @sudden_appearance If such fundamental knowledge is missing, I guess that there are more basic things unknown and reading the whole tutorial may be useful. – Michael Butscher May 07 '23 at 18:23

2 Answers2

1

Try initializing all the class-level variables inside the __init__ functions. Something like this should help:

class datapoint:
    def __init__(self, name, node_number=0, node_array_index=0, active=False, log_next=False):
        self.name = name
        self.node_number = node_number
        self.node_array_index = node_array_index
        self.active = active
        self.log_next = log_next

class node:
    def __init__(self, name):
        self.name = name
        self.address = [0]*8
        self.message_now = False
        self.datapoints = []
0

I believe it may be because of the "un-pythonic" method of declaring attributes of each of your classes. I say "un-pythonic" in that you do not initialize variables using "self.[variable_name]" and instead just initialize variables how you normally would if it were to be outside of a class.

It seems to me that the "datapoints" list is sharing values between the different "node" objects. So, you append "datapoint('Humidity')" to the "datapoints" list in node_list[0], and then you append "datapoint('Temperature')" to the "datapoints" list in node_list[1]. However, because there is only 1 object for the "datapoints" list, the value of this object is shared between different instances of the classes. So, the value of the "datapoints" list is now [datapoint('Temperature'), datapoint('Humidity')]. If you wish to fix this, simply initialize this as "self.datapoints = [ ]" instead of "datapoints = [ ]". It should look something like this:

class node:
    
    address = [0]*8
    name = " "
    message_now = False
    
    def __init__(self, name ):
        self.name = name
        self.datapoints = []

Note that if you wish to perform future operations with the "address", "name", and "message_now" variables, you will run into similar errors of different "node" class objects sharing values with one another when you only meant the values to be specific to each instance of the "node" object.

As a sidenote, it may be worth looking into having less ambiguous names for your variables. While looking into this issue, it was a bit difficult (at least for me, you may be different) to keep track of what exact objects I was referring back to. Conventional Python naming rules highly recommends having the names of classes be capitalized (thus changing "class datapoint" to "class Datapoint"). Furthermore, it may be worth differentiating between "datapoint" and "datapoints" by having them instead be "Datapoint" and "datapoints_list" respectively. This simply helps with readability and is of course all down to personal preference, but this should help with debugging and rereading code in the long run.

I hope this helps, please let me know if there's anything else I should clarify or if there are any nuances that I overlooked. Best of luck with your home project!