Skip to content Skip to sidebar Skip to footer

Function Modifies List

def make_Ab(A,b): n = len(A) Ab = list(A) for index in range(0,n): Ab[index].append(b[index][0]) print(A) return Ab.copy() A = [[0.0, 1.0, 1.0, 2.0], [

Solution 1:

The issue here is that, while you're not modifying the variable (which you can't do without global), you are modifying the value.

This can be a bit confusing at first. These two look like they do the same thing:

>>>a = [1, 2, 3]>>>a = a + [1]>>>a
[1, 2, 3, 1]
>>>a = [1, 2, 3]>>>a.append(1)>>>a
[1, 2, 3, 1]

But they're not. The first one is making a new list out of a and [1] and then binding that new list back to the name a. If there was some other reference to that same list, it would be unchanged. The second one, on the other hand, is changing the actual list object that a names. If there was some other reference to that same list, it would change.

>>>a = [1, 2, 3]>>>b = a>>>a = a + [1]>>>b
[1, 2, 3]
>>>a = [1, 2, 3]>>>b = a>>>a.append(1)>>>b
[1, 2, 3, 1]

What you're doing in your code is the second one, changing the value of the list object. Which means that every reference to that list object, even a name you don't have access to, will see the change.

But you're not modifying A itself, you're modifying list(A). Shouldn't that be a new copy of the list?

Yes, it is—but, even if Ab is a different list from A, Ab[0] is still the same list as A[0]. You've made a new list that references the same sublists as the original one. So when you mutate those sublists… same problem.

If you want to change this, you can do one of two things:

  • Copy all of the sublists, as well as the list, at the top of the function, so you mutate the copy instead of the original.
  • Don't use any mutating operations on the lists; build a new one.

The first one is a simple change: instead of Ab = list(A), do Ab = copy.deepcopy(A) or Ab = [list(sub) for sub in Ab].

The second one requires rewriting your code a bit:

def make_Ab(A,b):
    n = len(A)
    Ab = []        
    for index in range(0,n):
        Ab.append(A[n] + [b[index][0]])
    return Ab

(Or, of course, you can rewrite that as a list comprehension.)

Solution 2:

Passing Arguments to Function - Python

Python uses a mechanism, which is known as "Call-by-Object", sometimes also called "Call by Object Reference" or "Call by Sharing".

Call by Value - Immutable Arguments

If we pass immutable arguments like integers, strings or tuples to a function, the passing acts like call-by-value.

Call by Object or Call by Object Reference - Mutable Arguments

If we pass mutable arguments like lists and dictionaries to a function, they are passed by object reference.

Solution

The solution to your problem is to use deepcopy.

  1. Add from copy import deepcopy
  2. Replace Ab = list(A) with Ab = deepcopy(A)
  3. Replace return Ab.copy() with return Ab

main.py

from copy import deepcopy


def make_Ab(A, b):
    n = len(A)
    Ab = deepcopy(A)
    print("\nmake_Ab-before append: \n    A=", A)
    for index in range(0, n):
        Ab[index].append(b[index][0])
    print("\nmake_Ab-after append: \n    A=", A)
    return Ab

A = [[0.0, 1.0, 1.0, 2.0], [1.0, 3.0, 1.0, 5.0], [2.0, 0.0, 2.0, 4.0]]

b = [[1], [2], [3]]print("Before: make_Ab call, \n    A=", A)

Ab = make_Ab(A, b)

print("\nAfter: make_Ab call, \n    A=", A)
print("\nAfter: make_Ab call, \n    Ab=", Ab)

Output

enter image description here

Post a Comment for "Function Modifies List"