A brief analysis of references and copies in Python

  • 2020-04-02 14:23:42
  • OfStack

If an object 's value can be modified, the object is said to be mutable. If the value always be modified, the object is said to be immutable.

Mutable variable types, such as the list, set, custom types (equivalent to a reference type in c #);

Immutable types, such as string, Numbers, etc. (equivalent to value types in C#);

1. References and copies

When the = assignment operator is used in a program, such as a=b,

For immutable objects, a is created as a copy of b, a and b will point to different memory addresses, and a and b will be independent of each other.


def TestCopy():
    a = 10
    b = a
    a =20
    print (b) #b still is 10

But for mutable objects, a is created as a reference to b, the elements of a and b share the same memory address, and the elements of a and b share.

def TestRef():
    a=[1,2,3,4]
    b=a   #b is a reference to a
    print (b is a) # True
    b[2] = -100 #change an element in b
    print (a) # a also changed to [1,2,-100,4]

(2) shallow copy and shallow copy

To avoid mutable objects pointing to the same object, you must create a new copy, not a reference.
In python container objects (such as lists and dictionaries) can be used two copies: shallow and deep copy.
 
A shallow copy creates a new object, but populates the new object with references to the elements of the original object (which is equivalent to a copy if they are of the same type). You can use copy.copy() for shallow copying.


def TestShallowCopy():
    a = [ 1, 2, [3,4] ]
    b = list(a) # create a shallow copy of a
    print (b is a) #False
    b.append(100) #append element to b
    print (b)
    print (a) # a is unchanged
    b[2][0] = -100 # modify an element inside b
    print (b)
    print (a)  # a is changed

In this case, a and b share the same variable elements. So if you modify an element in one of the list objects, the other list object will also be modified.

Deep copy creates a new object while recursively copying all the elements that the object contains. Deepcopy can be implemented using copy.deepcopy().


def TestDeepCopy():
  import copy
  a = [1, 2, [3, 4]]
  b = copy.deepcopy(a)
  b[2][0] = -100
  print (b)  # b is changed
  print (a)  # a is unchanged

In this example, a and b are opposite list objects, and their elements are independent of each other.

Reference counting and garbage collection

All objects in python are reference counted. When an object is assigned a value or added to a container, its reference count increases. When del is used or a variable is assigned to another value, the reference count decreases.


def TestGarbageCollection():
  import sys
  print(sys.getrefcount(37))
  a = 37 # Creates an object with value 37
  print(sys.getrefcount(37))
  b = a # Increases reference count on 37
  print(sys.getrefcount(37))
  c = []
  c.append(b) # Increases reference count on 37
  print(sys.getrefcount(37))
  del a # Decrease reference count of 37
  print(sys.getrefcount(37))
  b = 42 # Decrease reference count of 37
  print(sys.getrefcount(37))
  c[0] = 2.0 # Decrease reference count of 37
  print(sys.getrefcount(37))
 
TestGarbageCollection()

The running result is:


11
12
13
14
13
12
11

Why are there 11 quotes in the first place? Who knows?


Related articles: