0

just registered at stackoveflow because of a weird class attribute change problem I encountered in python 3.6 (editor: spyder 3.1.4). Not sure how to describe it appropriately so my apology if similar problems have been asked before. Following is the problematic code snippet:

    class Node:
        def __init__(self, s = '', c = []):
            self.s = s
            self.c = c
    ...
    def somefunction(p):
        currentnode = a_node # a previous Node instance
        p_node = Node(s = p) # debugging showed after this step, p_node.c == []
        currentnode.c.append(p_node) # now, somehow p_node.c == [ p_node ], and still currentnode is not p_node
        currentnode = p_node

I have checked to make sure no accidental mutual references, and have changed the attribute Node.c from list() to set(), same thing happened. Any explanation on this accidental class attribute value change? Thanks a bunch!

  • One of the most infamous Python gotchas... We should have something on SO parsing Python code snippets for mutable default args and automatically closing the question as dup xD – bruno desthuilliers Oct 04 '17 at 08:36
  • I think I understand what the problem is. The `Node` class constructor creates a single reference to the same empty list every time a new class object is created. I found an ugly fix by changing the attribute `Node.c` to `NoneType`, but this generates a lot of burdensome `if` branches in other parts of my program. I guess now the question is: if a class attribute is default to empty `list()` or `set()`, how do we code it to generate new instance upon every call? – Slonymelion Oct 04 '17 at 09:21
  • My thanks to bruno for teaching me the term "mutable default argument". I've actually learned about it, but it's been years since I picked up python. Sorry for the dup question. – Slonymelion Oct 04 '17 at 09:30
  • the canonical fix is to define the default argument as `None` and in the `__init__` set it to an empty list (dict, set, whatever) if necessary - that way the client code doesn't have to test anything. You'll find an example here https://gist.github.com/BrunoDesthuilliers/bbbbac11361bb2947dccee25d1a54a92 – bruno desthuilliers Oct 04 '17 at 10:04

0 Answers0