0

I have the following Python code

def perm_list(l_0,l_1):
    res = 0
    l_01 = l_0
    l_11 = l_1

    if (l_01.sort() == l_11.sort()):
        res = 1
        return res 
    else:
        res = 0
        return res


a = [1,2,3]
b = [2,1,3]
perm_list(a,b)
print(b)

The result is [1,2,3]. It seems I only sort l_01, l_11, not l_0, l_1, why the entry b is affected?

AlphaF20
  • 583
  • 6
  • 14

2 Answers2

1

Because l_01 and l_0 are the same list.

You can check if they are the same by using the is operator

l_01 is l_0.  #will return True

This means that they both point to same address in memory or both have the same identity.

The fix is to do clone or create a deepcopy of your list.

l_01 = list(l_0)
#after that
l_01 is l_0 # will return False
Albin Paul
  • 3,330
  • 2
  • 14
  • 30
1

You have hit two concepts there: Python's "call by assignment" and "shallow copy".

  • Call by assignment

In Python, passing immutable types (like str) to a function, a copy of that argument is actually sent to the function. So modifying it won't affect the original variable.

Eg:

def func(my_str):
    my_str = "changed_string"

inp = "abcd"
print(inp) # abcd
func(inp)
print(inp) # abcd

But passing mutable types like list will not pass a copy of it, it rather send a reference to that list (think of like a pointer to the list). So modifying a list coming in as an argument will modify the original list.

Eg:

def func(my_list):
    my_list += [4,5,6] # notice the += operator

inp = [1,2,3]
print(inp) # [1,2,3]
func(inp)
print(inp) # [1,2,3,4,5,6]

But, if you reassign the incoming argument, then that won't affect the original variable.

Eg:

def func(my_list):
    my_list = [4,5,6]

inp = [1,2,3]
print(inp) # [1,2,3]
func(inp)
print(inp) # [1,2,3]

Now that call-by-assignment is clear, let's look at shallow and deep copy.

  • Shallow and Deep copy

In you code, the following part is a Shallow copy:

l_01 = l_0
l_11 = l_1

Here, both l_01 and l_0 point to the same list. So using both variables will eventually modify the same list.

Eg:

my_list1 = [1,2,3]
print(my_list1) # [1,2,3]

my_list2 = my_list1 # SHALLOW COPY

print(my_list2) # [1,2,3]

my_list2[0] = 10

print(my_list1) # [10,2,3]
print(my_list2) # [10,2,3]

Now, to avoid this, you have to do a deepcopy. One example for list would be to use the list() constructor.

Eg:

my_list1 = [1,2,3]
print(my_list1) # [1,2,3]

my_list2 = list(my_list1) # DEEP COPY (not recursive deep copy!!)

print(my_list2) # [1,2,3]

my_list2[0] = 10

print(my_list1) # [1,2,3]
print(my_list2) # [10,2,3]

There are several ways to do deep copy: using the slicing operator, using the copy library etc. Using the copy.deepcopy method to make copies ensures recursive deep copies.

Rahul Bharadwaj
  • 2,555
  • 2
  • 18
  • 29