0

I created a linked list in python, and I created a pointer variable pointing to the same node.

However, when I try to update the pointer, the linked list doesn't update. It only updates when I use the orignal notation. Here are the three lines of concern, followed by the code snippet:

pointer = self.storage[index]
pointer = pointer.next #does not work
self.storage[index] = self.storage[index].next #DOES work.
def remove(self, key):

        pair = LinkedPair(key,None)
        index = self._hash_mod(pair)

        pointer = self.storage[index]
        prev = None
        while pointer:
            if pointer.key == pair.key:
                if prev is None:  #at the beginning of the linked list, set the head to equal the next value
                    print(self.storage[index] == pointer) #true
                    self.storage[index] = self.storage[index].next
                    pointer = pointer.next
                    # pointer = pointer.next
                    break
                # self.display(pointer,prev,' pointer == pair')
                prev.next = pointer.next
                del pointer
                break
            else:
                prev = pointer
                pointer = pointer.next

            # self.display(pointer,prev,' post shifting')
            # self.storage[index] = self.storage[index].next
        return -1
3
  • Yes, Python doesn't have pointers. Doing pointer = self.storage[index] and pointer = pointer.next simply assigns two different objects to the same variable in succession, but that doesn't affect those objects at all. Commented Jan 15, 2020 at 5:51
  • 1
    @juanpa Can you please explain why it does not affect the objects ? If I try to create a small link list and try to modify its value as done above that works fine for me. Commented Jan 15, 2020 at 6:09
  • Assignment isn't a mutation. It is simply changing a reference. Commented Jan 15, 2020 at 6:12

1 Answer 1

1

Variables in python are just names for object, and assigning to them just changes the object designated by that name.

However, when assigning to elements of a list, you are changing the object referenced by that position in the list.

Thus:

pointer = self.storage[index] # 1
pointer = pointer.next  # 2
self.storage[index] = self.storage[index].next  # 3

(1) Makes pointer a name for the object referenced at storage[index]

(2) On the right side of the assignment =, you look for the name attribute of the object referenced by pointer. This is self.storage[index].name. The assignment will make the pointer variable refer to self.storage[index].name. To update the self.storage list, you need to operate on the list object itself. As opposed, self.storage[index], as referenced by pointer, is just "some object". You don't even have a way to get back to the list from there, so there's no way to change the list here.

(3) Here, however, you are changing the list self.storage, replacing the element at index. You could have doneself.storage[index] = pointer` at this point, with the same effect.

Of course python works with references (or pointers) under the hood. my_list[1] = obj doesn't allocate space for obj, it will store a reference to it. But local and global variables are not references, they are names.

In the end, global and local namespaces are just mapping variable names to objects. They are usually just normal dictionaries. You can see these by calling globals() and locals(). Or you can "implement" variable assignment just by changing that dictionary:

foo = 1
globals()["foo"] = 2
print(foo)  # --> 2

Python assignment to variables is different than assignment to mutable objects like lists or dictionaries. Let's consider the following statements:

a = 1     # 1
b = [1]   # 2
b[0] = 2  # 3

The first two assignments are doing the same. They are creating (or updating) global variables a and b, and map them to the int object 1 and to the list object [1], respectively. You'll have:

globals()
{
   ...
   "a": 1,
   "b": [1]
   ...
}

The third assignment is completely different. The assignment of this type is actually implemented by the object on the left. From the docs:

When a target is part of a mutable object (an attribute reference, subscription or slicing), the mutable object must ultimately perform the assignment and decide about its validity, and may raise an exception if the assignment is unacceptable.

This means that the third statement is implemented by the list object itself. Now the list in python keeps references to objects (it does not copy the objects). b[0], when used in an expression, is implemented by a special method of the list object and will return the object referenced by the list at position 0. b[0] = 2 is actually calling a special method of the list object, with the index (0) and the target object (2) as arguments, and the list implementation decides how it updates itself: it will change the reference at index 0 to the new object.

This difference is embedded in python's assignment statement. I've liked you the full reference, too.

More details:

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your response. I don’t quite follow what you are saying in step 2. Could you reword it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.