zchtodd
zchtodd

Reputation: 1150

Python references

I have come across a situation that I believe has revealed a gap in my understanding of how references work in Python.

Suppose that we have two classes:

class A:
    def __init__(self):
        self.x = [1,2,3]

    def modify(self):
        self.x.append(4)

    def reset(self):
        self.x = []

class B:
    def __init__(self, x):
        self._x = x

    def say(self):
        print self._x




a = A()
b = B(a.x)

b.say()
a.modify()
b.say()
a.reset()
b.say()

The output I expected was:

[1, 2, 3]
[1, 2, 3, 4]
[]

The output I got was:

[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4]

It seems that when I called reset() and set self.x to a new list, the reference held by B became independent and lived on, thereby becoming a copy instead of a reference. Is this a correct understanding?

Upvotes: 1

Views: 211

Answers (3)

Eric Fortin
Eric Fortin

Reputation: 7603

In fact, it is not _x in B that became a copy but x in A that became another list.

Upvotes: 0

Frost.baka
Frost.baka

Reputation: 8021

When you are assigning a.x to [], you are not cleaning the array rather assign a new empty array to a.x while it's reference: b._x is kept intact. If you want to modify and array in place, in your case delete all of it's contents do this:

del a.x[:]

Upvotes: 3

Sven Marnach
Sven Marnach

Reputation: 601471

The reset() method

def reset(self):
    self.x = []

does not modify the object stored in self.x -- it rather creates a new empty list, which is then stored in self.x. The old list is not altered (and since it is still referenced by b._x, it is also not garbage collected). To get the behaviour you are after, use

def reset(self):
    del self.x[:]

to empty the existing list instead of creating a new one.

Upvotes: 10

Related Questions