Python deep copy is not perfect

I believe you are already familiar with the difference between shallow copy and deep copy of Python. Shallow copy is to reapply a memory space for the original object, but if the sub-objects of the original object are mutable objects, there is still a reference relationship; deep copy It is also to reapply for memory space and copy to the new object by creating a new child object in a recursive manner. Both the original object and its child objects are independent of each other, and the new object is not related to the original object.

However, deep copy is not perfect. Look at the code first. You can predict the output of the program first, and then execute it to see if the expectations are consistent.

import copy
x =[1]
x.append(x)
y = copy.deepcopy(x)

# What is the output of the following command?
x == y

When the program executes to line 3, x is already an infinitely nested list, but when it executes to line 4, the program is deeply copied and new sub-objects are recursively created, but no memory overflow occurs. Wrong, why is this?

In fact, this is because the deep copy function deepcopy maintains a dictionary to record the copied objects and their IDs. During the copying process, if the object to be copied is already stored in the dictionary, it will be returned directly from the dictionary. We can understand by looking at the corresponding source code:

def deepcopy(x, memo=None, _nil=[]):"""Deep copy operation on arbitrary Python objects.
      
 See the module's __doc__ string for more info."""
  
 if memo is None:
  memo ={}
 d =id(x) #Query the id of the copied object x
 y = memo.get(d, _nil) #Query whether the object is already stored in the dictionary
 if y is not _nil:return y #If the object to be copied is already stored in the dictionary, return directly
        ...

When the program executes to line 7 to compare the values of two objects, it will report an error. What is the reason?

Because x is an infinitely nested list, and y is deeply copied from x. In theory, x == y should be True, but when the comparison operator ==, the == operator will traverse the object recursively All values, and compare them one by one. In order to prevent the stack from crashing, Python has to limit the number of recursion levels, and it will not go on endlessly, so when the limit is reached, the Python interpreter will jump out an error:

>>> import copy
>>> x=[1]>>> x.append(x)>>> x
[1,[...]]>>> y = copy.deepcopy(x)>>> x == y
Traceback(most recent call last):
 File "<stdin>", line 1,in<module>
RecursionError: maximum recursion depth exceeded in comparison
>>>

The reason is also that the number of recursion levels in Python is limited. There is a method in the sys module to get the number of recursion levels:

>>> import sys
>>> sys.getrecursionlimit()1000

Of course, you can also reset the number of recursion levels:

>>> import sys
>>> sys.getrecursionlimit()1000>>> sys.setrecursionlimit(10000)>>> sys.getrecursionlimit()10000

Is it possible to set infinity? In theory, it is possible, but your program crash is also certain, you can do a test yourself.

To sum up, the disadvantage of deep copy is that if there is a reference to itself in the object, then it is easy to have an infinite loop, but reference and shallow copy do not, as follows:

>>> import copy
>>> x=[1]>>> x.append(x)>>> x_alias = x
>>> x_copy = copy.copy(x)>>> x_deepcopy = copy.deepcopy(x)>>> x == x_alias
True
>>> x == x_copy
True
>>> x == x_deepcopy
Traceback(most recent call last):
 File "<stdin>", line 1,in<module>
RecursionError: maximum recursion depth exceeded in comparison
>>>

Recommended Posts

Python deep copy is not perfect
Python 3.9 is here!
Why python is popular
Python is short-crawling music
Python is slowly fading
Is python an interpreted language?
Is python an interpreted language
Python is short-world epidemic map
Deep understanding of Python multithreading
Python is short _SVM test
Is python code case sensitive
What is introspection in python
What is object-oriented in python
What is Python variable scope