0

I have a simple example. The function test_list_change should change the list passed to it as a parameter. And inside this function there is a call to sub-routine test_list_change_2 which should change the same list.

The problem is, that the result list doesn't contain changes made by the test_list_change_2 subroutine

Why it could be?

Here is the example:

def test_list_change(lst):
    if len(lst) < 3:
        lst.append("the last one")
        test_list_change_2(lst)

def test_list_change_2(lst):
    lst = ["the very last one"]

string_list = ["first", "another one"]
test_list_change(string_list)
print (string_list)

The output:

['first', 'another one', 'the last one']

Vcitor
  • 53
  • 5
  • just returning `return ["the very last one"] ` is the same as what you are trying to do in your function, I don't think your code is going to do what you expect – Padraic Cunningham Jan 30 '15 at 20:52

5 Answers5

3

You need to actually change the original list/object:

def test_list_change(lst):
    if len(lst) < 3:
        lst.append("the last one")
        test_list_change_2(lst)

def test_list_change_2(lst):
    lst[:] = ["the very last one"] # changes original list object

string_list = ["first", "another one"]
test_list_change(string_list)
print (string_list)
['the very last one']

If you want to change around the elements:

def test_list_change_2(lst):
    lst[:-1] = ["the very last one"]
    lst[:] = lst[::-1]

string_list = ["first", "another one"]
test_list_change(string_list)
print (string_list)
['the last one', 'the very last one']

You can manipulate the list whatever way you like but you need to actually refer to the original list object, reassigning a name won't change the lst it will just assign that name to another object.

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
1

You probably got confused how things work in python with "passing by reference" and thought that since it is passed by reference, so the original list should be updated to ["the very last one"].

It works in the following manner:

1) before test_list_change is called, there is a name "string_list" and python creates a object ["first", "another one"] which is assigned to string_list

2) now in test_list_change, a new name "lst" is assigned with ["first", "another one"]. So now both names are assigned with the same object. It is then appended and changed to ['first', 'another one', 'the last one'], pointed by both string_list and lst

3) In test_list_change_2, before you do the assignment, there exist another local lst name which points to ["first", "another one", 'ths last one']. Then python creates another object ['the vary last one'] and replaces the value of the local lst variable.

4) string_list still points to ['first', 'another one', 'the last one']

So another way to put it, variables are just names passed around and objects are managed 'by reference'.

dhu
  • 718
  • 6
  • 19
0

You need to return ["the very last one"] in test_list_change_2 :

def test_list_change_2():
    return ["the very last one"]

and assign the result of function to lst in first function :

def test_list_change(lst):
    if len(lst) < 3:
        lst.append("the last one")
        lst= test_list_change_2()

Note that actually you dont need a function here !!! you can do this assignment in the firs function .

Mazdak
  • 105,000
  • 18
  • 159
  • 188
  • the lst was assigned new value, isn't it? _lst= ["the very last one"]_ – Vcitor Jan 30 '15 at 20:46
  • No, the list wasn't assigned a new value. The name `lst` had a new list object assigned to it. The object passed in and given the name `lst` is unaffected. – paidhima Jan 30 '15 at 20:47
  • @Vcitor assignment is a change but for such tasks you dont need do more work with function as it waste the memory ! – Mazdak Jan 30 '15 at 20:50
  • If the only change you make to the code is adding `return lst` to `test_list_change_2`, the output will still be what the OP has now, because the returned value isn't assigned to anything in `test_list_change`, and even if you did `lst = test_list_change_2(lst)`, the change wouldn't propagate to `string_lst`. – Kevin Jan 30 '15 at 20:50
  • @paidhima, and how can I change the original object with the new value, to replace it with list only with one element with value "the very last one"? – Vcitor Jan 30 '15 at 20:54
  • @Vcitor whats your desire out put ? – Mazdak Jan 30 '15 at 20:55
  • @Kasra AD, it's just an example. i have another function which is more complicated and doesn't work as expected. it's quite big that is why I posted a similar example here. – Vcitor Jan 30 '15 at 20:56
  • @Vcitor imean that whats your expected out put for `["first", "another one"]` ? – Mazdak Jan 30 '15 at 20:57
0

Your test_list_change2 procedure is doing lst = ['the very last one']. It's simply assigning a new object to the local name lst. It has no effect whatsoever on the list passed in to that procedure.

I'm not sure what you're trying to accomplish. If you want test_list_change2 to add to lst, just append it. Can you clarify?

paidhima
  • 2,312
  • 16
  • 13
0

If you are trying to get just "the very last one" to be in the list then:

def test_list_change(lst):
    if len(lst) < 3:
        lst.append("the last one")
    lst = test_list_change_2(lst)

def test_list_change_2(lst):
    for i in range(len(lst)):
        lst.pop()
    lst.append("the very last one")


string_list = ["first", "another one"]
test_list_change(string_list)
print (string_list)
Dan Simmons
  • 116
  • 4