Does pass-by-reference only work if I use the index?


#1

In exercise 13, i'm expected to write:

def double_list(values):
    for element in range(0, len(values)):
        values[element] *= 2
    return values

But on my first try, i wrote it like this:

def double_list(values):
    for element in values:
        element *= 2
    return values

Why does my way not work? I thought every variable in python was a reference to an object, and therefore in "my way", element references values[current_position].


#2

In Exercise 15 it explains that the two methods you've described do work differently. You're right that only by using the index can you modify the original argument.

The first version - for element in range() will allow you to modify the argument passed to it.

The second version - for element in values() won't let you modify it.

I'm afraid I don't know enough Python to explain why this is the case. Perhaps the first method uses pointers behind the scenes when you access the elements directly.


#3

Thank you for the time taken to reply, but my question is specifically why doesn't python allow me to modify the original list with the second way.


#4

TL:DR: It's all in the scope of things!

The answer
Ok, we need to do some testing to figure out what's happening under the hood.

First let's create a function to get out object id number so we can compare them during a loop, and a list to work on.

the_list = [1, 2, 3, 4, 5]

response = {1: "Value ID: %s, List[Index} ID: %s, Match: %s"}
def get_id(thing_to_check):
    print("ID of List: %s" % id(thing_to_check))
    for index, value in enumerate(thing_to_check):
        print(response[1] % (id(value), id(thing_to_check[index]),
                             (True if id(thing_to_check[index]) == id(value) else False)))

You will love the above code :smile:

Also, we can check the id of the object before use too with a simple id() call.

So what the above code does is to check a list and it's values to see if they have the same id during a for loop which they do right now.

The reason is because as you know they are a reference to the object.

Now what we need to do is to try and change the item during a loop and see what happens.

FUNCTION: Change value of irritable during loop.

response = {1: "BEFORE: Value ID: %s, List[Index} ID: %s, Match: %s",
            2: "AFTER:  Value ID: %s, List[Index} ID: %s, Match: %s",
            3: "LIST ID: %s, LIST ITEMS ID: %s"}

def get_id(thing_to_check):
    print(response[3] % (id(thing_to_check), [(index+1, id(id_of)) for index, id_of in enumerate(thing_to_check)]))
    for index, value in enumerate(thing_to_check):
        print(response[1] % (id(value), id(thing_to_check[index]),
                             (True if id(thing_to_check[index]) == id(value) else False)))
        value += 1
        print(response[2] % (id(value), id(thing_to_check[index]),
                             (True if id(thing_to_check[index]) == id(value) else False)))

Oh boy that's a ton of code to check something like this. :wink:

Ok now from my second codebit you can easily tell that when we change the value it changes its' id value.

Now you might be wondering why that is. Well you already stated why but let me clarify. You are working with a reference to that value.

Finally it all becomes a scope issue,

EXAMPLE:

level = [1, 2, 3]
for lev in level:
    print("lev:" ,lev)
    lev += 1
    print("lev:" ,lev)
    for l in range(lev):
        print("l:",l)
        l -= 1
        print("l:",l)

As you can see when we enter the loop, we are at the global scope of things. Next inside the loop we are at the loops' scope of things, which means that if we take the namespace of the variable we are using and override it it will get a new id and value.

The same applies for the inner most loop, it is at an entirely different scope and you can override the value of the previous loop easily.

Once the loop is executed it preforms garbage collections on the stuff no longer in scope so the override is no longer in effect thus it is able to continue normal operations.

I hope this helps to alleviate any thing you do not understand.

If not ask freely!