0

I was trying to implement a shortest path algorithm in python. I ran into some trouble when I attempted to connect my points on the path.

I have a class called NODE I made an array of these nodes and then created new nodes in them like this:

nodes = []
for r in range ( 0, 3 ):
    for c in range ( 0, 3 ):
        nodes.append( NODE( c*WIDTH/20 + 30, r*HEIGHT/20 + 30, 10 ) )

This created nodes, which is fine, I can draw them just fine.
At first I attempted connecting them by adding a list of node objects into the the NODE class. I ran into some issues, I thought the problem is with the recursive classes, so to test I did this.
Where connections is a blank array within the NODE class.

nodes[0].connections.append( 0 )
print nodes[0].connections

nodes[1].connections.append( 1 )
print nodes[1].connections
print nodes[0].connections

This is where I found the problem, Maybe I'm just being stupid, or It's a language thing ? Dunno, but I thought I'd ask.

The output is this:
[ 0 ]
[ 0, 1 ]
[ 0, 1 ]

As you can see, I only added 1 object to the connections list in the index 1. However when I print the contents, I see two.... And this confuses me.

suli
  • 41
  • 6
  • 1
    This is really hard to answer without seeing a [mcve] that includes the actual `NODE` class. – Kevin Jun 06 '17 at 18:27
  • 2
    Let me guess, `class Node` has a static field `connections` instead of initializing `connections` in the constructor to a new list, so that all objects share a single connection list? Show your `Node` class, please. – dhke Jun 06 '17 at 18:29
  • 1
    I'm going to go ahead and say this is a duplicate of [The mutable default argument](https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument). – Aran-Fey Jun 06 '17 at 18:30
  • yep. Thats the problem. I was writing it as though I would write something in Java or cpp. Thanks for the help guys ! – suli Jun 06 '17 at 19:28
  • Which one is the problem? A static property or a mutable default argument? –  Jun 06 '17 at 20:00
  • I had the array defined at the body of the class and not within the constructor – suli Jun 06 '17 at 20:59

1 Answers1

3

Possibilty 1: your code looks like this:

class NODE:
    connections = []
    def __init__(self, value):
        self.value = value

nodes = [NODE(23), NODE(42)]

nodes[0].connections.append( 0 )
print nodes[0].connections
nodes[1].connections.append( 1 )
print nodes[1].connections
print nodes[0].connections

Solution: class instance attributes should be defined inside __init__. If you define connections at the class level, then every single instance of NODE will share the same one connections list.

class NODE:
    def __init__(self, value):
        self.value = value
        self.connections = []

Possibility 2: your code looks like this:

class NODE:
    def __init__(self, value, connections = []):
        self.value = value
        self.connections = connections

nodes = [NODE(23), NODE(42)]

nodes[0].connections.append( 0 )
print nodes[0].connections
nodes[1].connections.append( 1 )
print nodes[1].connections
print nodes[0].connections

Solution: the default value in an argument list is created only once, so all instances of NODE using that default value will share the same one list. use a non-mutable sentinel value to indicate that no argument was passed. None is usually suitable for this task.

class NODE:
    def __init__(self, value, connections = None):
        self.value = value
        if connections is not None:
            self.connections = connections
        else:
            self.connections = []
Kevin
  • 74,910
  • 12
  • 133
  • 166
  • yea this is it. Thanks for answering ! This is gonna fix a lot of my other problems too ! – suli Jun 06 '17 at 19:26