SoFunction
Updated on 2024-11-15

The append shallow copy mechanism in Python explained in detail

Append Shallow Copy Mechanism in Python

The most intuitive thing to understand about deep and shallow copies is this:

  • Deep copy: the copy is so deep that it opens up a new block of memory and copies all the content being copied;
  • Shallow copy: the degree of copying is shallow, only the first address of the original data is copied, and then through the first address of the original data, to get the content.

The advantages and disadvantages of these two are compared:

  • Deep copy is a high degree of copying, copying the original data into a new memory space. Changes to the copied content do not affect the original data content. However, deep copy is time consuming and takes up memory space.
  • Shallow copies copy to a low degree, copying only the address of the original data. In fact, the address of the copy is pointing to the original data address. Modifying the content of the copy is done by pointing the current address to the original data address to modify it. So modifying the content of the copy will affect the content of the original data. However, shallow copying is time-consuming and takes up less memory space.

Python Memory References

In C, when declaring a variable, int a, int b, these two statements give two different memory spaces for the variables a and b. Then when assigning a value, the corresponding value is stored in the corresponding memory space. But the assignment of variables in Python is very different from C. Consider the following code:

>>> a = 2
>>> b = 2
>>> id(a)
140736259334576
>>> id(b)
140736259334576

The id function is used to get the memory address of the object, and it is surprising to find that variable a and variable b have the same memory address!

In Python, Mr. becomes an object and the variable then references the object, in this example, 1 is the object and then a references 1. Since the constant is an immutable type, the memory space for 1 is the same, so a, and b references use a block of memory space. Although the variable names are different, the objects they reference are the same.

Of course the example above is of type int, which is immutable. What if it's a list or a dict? Take a look at the following example:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id(a)
3145735383560
>>> id(b)
3145735414984

Memory address inconsistency! Based on this, let's step into today's topic to look at the append method shallow copy mechanism, what are the pitfalls!

The append method shallow copy mechanism

The append method in Python is a commonly used method to add an object to the end of a list. I'm sure you've all used it before, right? Has anyone bothered to dig deeper into the usage of this function? There can be a big pitfall here!

Let's look at an example:

>>> a = [1, 3, 5, "a"]
>>> b = []
>>> (a)
>>> b
[[1, 3, 5, 'a']]
>>> ("aha")
>>> b    # surprise?
[[1, 3, 5, 'a', 'aha']]

Thinking about it, it is clear that there is no operation on b after the third line, so why does b change?

Returning to today's topic, the append method is, in fact, a shallow copy. In Python, object assignments are actually references to objects, and when you create an object and then assign it to another variable, Python doesn't copy the object, it just copies a reference to the object, which is a shallow copy.

Let's look at it step by step. First, (a) is a shallow copy of a, resulting in b=[[1, 3, 5, 'a']], but b[0] is the same object referenced by a, which can be verified by the id function:

>>> id(b[0])
3145735177480
>>> id(a)
3145735177480

As you can see, b[0] points to the same memory address as a.

Next, the code executes (0), the list is of mutable type, this step adds 0 to the end of the list at the original address, the content of the original address is changed but the address does not change (you can understand the list in Python as a chain list, so the address of this list does not change, which is equivalent to the head node of the chain list), so the content of a and b[0] is changed at the same time, which is why the append operation on a This is why an append operation on a is followed by a change in b.

All of this occurs on the premise that the operation is performed on the contents of the same address, and so affects all variables pointing to that address.

So, when you use the append function on a daily basis, you need to change the shallow copy to a deep copy, and there are two solutions:

  • (list(a))
  • (a[:])

Still with the above example, let's see if the result of these two methods actually solves the append shallow copy problem.

>>> a = [1, 3, 5, "a"]
>>> b = []
>>> (list(a))
>>> b
[[1, 3, 5, 'a']]
>>> (0)
>>> a
[1, 3, 5, 'a', 0]
>>> b
[[1, 3, 5, 'a']]
>>> a = [1, 3, 5, "a"]
>>> b = []
>>> (a[:])
>>> b
[[1, 3, 5, 'a']]
>>> (10)
>>> a
[1, 3, 5, 'a', 10]
>>> b
[[1, 3, 5, 'a']]

How about that, is the problem solved! So in your daily use, you must avoid the problems caused by shallow copying!

This append pitfall is also something I noticed while brushing up on leetcode: 77. combinatorial, with the problem solved as:

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        def traversal(n, k, start_index):
            if len(path) == k:
                (path[:])   # Essence here, to fix the shallow copy problem here!
                return
            
            for i in range(start_index, n + 1):
                (i)
                traversal(n, k, i + 1)
                ()
        
        path = []
        result = []
        traversal(n, k, 1)
        return result

Failure to deal with the shallow copy problem at line 5 leads to the following result at the run:

Why? Because of backtracking ah, in the above code in line 11, has been backtracking up, so the results run out to become an empty list!

So, when brushing up on backtracking questions, if you're using Python, be sure to keep this in mind!

Supplementary: Python append() with deep copy, shallow copy

deep or shallow copy

In Python, object assignments are actually references to objects. When you create an object and assign it to another variable, Python doesn't copy the object, it just copies a reference to the object, which we call a shallow copy.

In Python, you can use the deepcopy method in the copy module, called deepcopy, in order to make two variables complement each other when an assignment operation is performed.

append() function

When an object of type list is appended, a reference to the object is actually appended.

id() Function: Returns a unique identifier for an object, which can be analogized to the address of that object in memory.

>>>alist = []
>>> num = [2]
>>> ( num )
>>> id( num ) == id( alist[0] )
True

As shown in the above example, when num changes (provided id(num) doesn't change), the contents of the alist will change. This often has unintended consequences, and can be avoided by using a deep copy:

( ( num ) )

to this article on the Python append shallow copy mechanism is introduced to this article, more related Python append shallow copy content please search for my previous articles or continue to browse the following related articles I hope that you will support me in the future more!