python基础面试题总结

1.python中深拷贝和浅拷贝的理解

  自己理解:浅拷贝,只是拷贝引用,不开辟新的空间存储拷贝内容。

       深拷贝,就是在内存中,开辟一个新的内存地址,将拷贝内容放到新的地址中去。

  验证:对于数字,字符串,元祖这种不可变类型的数据,深拷贝和浅拷贝拷贝的是内存地址的引用。

  不可变类型

import copy


# 不可变类型---数值 int float
a1 = 1
b1 = copy.copy(a1)
print(id(a1))  # 8791199896608
print(id(b1))  # 8791199896608
c1 = copy.deepcopy(a1)
print(id(c1))  # 8791199896608
d1 = a1
print(id(d1))  # 8791199896608


# 不可变类型---元祖
a2 = (1,2)
b2 = copy.copy(a2)
print(id(a2)) # 35120520
print(id(b2)) # 35120520
c2 = copy.deepcopy(a2)
print(id(c2)) # 35120520
d2 = a2
print(id(d2)) # 35120520


# 不可变类型---字符串
a3 = "china"
b3 = copy.copy(a3)
print(id(a3)) # 43407152
print(id(b3)) # 43407152
c3 = copy.deepcopy(a3)
print(id(c3)) # 43407152
d3 = a3
print(id(d3)) # 43407152

  可变类型:字典,列表

 

a1 = [1,2,3]
b1 = copy.copy(a1)
print(id(a1)) # 43298888  
print(id(b1)) # 43270024
c1 = copy.deepcopy(a1)
print(id(c1)) # 43299144
d1 = a1
print(id(d1)) # 43298888

 

 图像理解浅拷贝:浅拷贝是在内存中创建了一个新的内存地址,用来存放新的列表,b指向这个列表,所以a和b在内存中的地址不一样。因此说浅拷贝只是拷贝了列表这个对象,而不是里面的数据。

 

  如何证明,浅拷贝只是拷贝了对象,而不是里面的内容呢?

a1 = [1,2,3]
b1 = copy.copy(a1)
print(id(a1)) # 43204552
print(id(b1)) # 43204424
for i in a1:
    print(id(i))

8791195833376
8791195833408
8791195833440

for i in b1:
    print(id(i))

8791195833376
8791195833408
8791195833440

  所以打印a1和b1的内存地址不同,但是结果却相同。

print(a1)
print(b1)    
[1, 2, 3]
[1, 2, 3]

  另一种方式证明,浅拷贝只是拷贝对象,而里面的数据还是指向原来对象的数据。

import copy

a1 = [1,2,3,[4,5,6]]
b1 = copy.copy(a1)
print(a1)
print(b1)

[1, 2, 3, [4, 5, 6]]
[1, 2, 3, [4, 5, 6]]

a1[3].append(4)  # 也就是说b1里面下标为3的元素是指向a1里面下标为3的元素,所以才会打印出一样的效果。
print(a1)
print(b1)

[1, 2, 3, [4, 5, 6, 4]]
[1, 2, 3, [4, 5, 6, 4]]

  下面的例子也直接能证明这一点

import copy

a1 = [1,2,3]
b1 = copy.copy(a1)
print(a1)
print(b1)

[1, 2, 3]
[1, 2, 3]

a1.append(4)  # 此时a1中有四个元素,此时b1中只有三个元素,b1中没有第四个元素指向a1中新的元素,所以打印结果如下。
print(a1)
print(b1)

[1, 2, 3, 4]
[1, 2, 3]

  python中产生浅拷贝效果的地方:

     1.列表的切片

a = [1,2,3,4,5,7,8,9,10]
b = a[1:5]
print(a)
print(b)

[1, 2, 3, 4, 5, 7, 8, 9, 10]
[2, 3, 4, 5]

a[1] = "2"  # a 中下标为1的元素新建立了一个内存地址,存储的是"1"
a[2] = "3"
a[3] = "4"
a[4] = "5"
print(a)
print(b)   # b 中下标为1的元素指向的是原来这个数据1在内存中的地址。

[1, '2', '3', '4', '5', 7, 8, 9, 10]
[2, 3, 4, 5]

    2. 使用copy模块中的copy()函数

 图像理解浅拷贝:

import copy
a = [1,2,3,[4,5,6]]   # 对于不可变类型,深拷贝也只是拷贝引用,但是对于可变类型[4,5,6],深拷贝会拷贝一个新的对象,多以id值不一样,那么当[4,5,6]的数据进行增加时,深拷贝的后的对象会发生变化吗?
b = copy.deepcopy(a)
print(id(a))
print(id(b))

43138824
43167944

for i in a:
    print(id(i))

8791199896608
8791199896640
8791199896672
43138952

for i in b:
    print(id(i))

8791199896608
8791199896640
8791199896672
43204232
import copy
a = [1,2,3,[4,5,6]]
b = copy.deepcopy(a)

print(a)
print(b)

[1, 2, 3, [4, 5, 6]]
[1, 2, 3, [4, 5, 6]]

# 当a[3]中的元素进行增加数量时,因为深拷贝后列表中的第三个元素指向发生了变化,重新生成了一个列表,指向了新列表,所以,原列表增加,新列表不增加。但是列表中的元素,还是指向原来列表中的元素。
a[3].append(7) 

print(a)
print(b)

[1, 2, 3, [4, 5, 6, 7]]
[1, 2, 3, [4, 5, 6]]

for i in a[3]:
    print(id(i))

8791199896704
8791199896736
8791199896768
8791199896800

for i in b[3]:
    print(id(i))

8791199896704
8791199896736
8791199896768

# TODO 字典

# TODO 元祖

 

 

总结:

  • Python中对象的赋值都是进行对象引用(内存地址)传递
  • 使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.
  • 如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝
  • 对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有被拷贝一说
  • 如果元祖变量只包含原子类型对象,则不能深拷贝

 

posted @ 2019-09-17 19:14  张京墨  阅读(253)  评论(0编辑  收藏  举报