当前位置:   article > 正文

解惑 python3 可变类型与不可变类型 , is 与 == 区别 , 变量赋值、深拷贝与浅拷贝_python3 == 和is

python3 == 和is

一、可变类型与不可变类型

(1)可变类型(mutable):列表、字典、集合

(2)不可变类型(unmutable):数字、字符串、元组

简单点说:可变对象就是允许对自身进行修改;不可变对象不允许对自身进行修改,如果修改了就不是原来的对象了,我们可以用内置函数 id() 来判断!!!

注意:这里的可变不可变指的是内存中的那块内容(value)是否可以被改变。如果是不可变类型的话,在对对象本身操作的时候,必须在内存中新申请一块区域(因为老区域不可变)。如果是可变类型,在对对象操作的时候,不需要在其他地方申请内存,只需要在此对象后面连续申请(+ / -)即可,也就是它的address会保存不变,但是区域会边长或变短。

可以使用内置函数 id() 来确认对象的身份在两次赋值前后是否发生变化。

不可变类型有什么好处?如果数据是不可变类型,当我们把数据传给一个不了解的API时,可以确保我们的数据不会被修改。如果我们要操作一个从函数返回的元组,可以通过内置函数 list() 把它转换成一个列表。(当被问到列表和元组的区别时,可以说这个!!!)

 

 二、==  与 is  在对象间的比较

(1) == 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。默认会调用对象的__eq__()方法

(2)is 比较的是两个实例对象是不是完全相同,他们是不是同一个对象,占用的内存地址是不是一样的。即比较id是否相同

简单点来说:

(1) == 比较操作符是用来判断两个对象的 value是否相等

(2) is 同一性操作符是用来判断两个对象的 id是否相同

(3)注意:is 运算符比==效率高,在变量和None进行比较时,应该使用is

例子:

  1. >>> a = 1 #a和b为数值类型
  2. >>> b = 1
  3. >>> a is b
  4. True
  5. >>> a == b
  6. True
  7. >>> a = 257 #a和b为数值类型
  8. >>> b = 257
  9. >>> a is b
  10. False
  11. >>> a == b
  12. True
  13. >>> a = 'python' #a和b为字符串类型
  14. >>> b = 'python'
  15. >>> a is b
  16. True
  17. >>> a == b
  18. True
  19. >>> a = (1,2,3) #a和b为元组类型
  20. >>> b = (1,2,3)
  21. >>> a is b
  22. False
  23. >>> a == b
  24. True
  25. >>> a = [1,2,3] #a和b为list类型
  26. >>> b = [1,2,3]
  27. >>> a is b
  28. False
  29. >>> a == b
  30. True
  31. >>> a = {'a':1,'b':2} #a和b为dict类型
  32. >>> b = {'a':1,'b':2}
  33. >>> a is b
  34. False
  35. >>> a == b
  36. True
  37. >>> a = set([1,2,3])#a和b为set类型
  38. >>> b = set([1,2,3])
  39. >>> a is b
  40. False
  41. >>> a == b
  42. True

注意:python仅仅对比较小的整型对象进行缓存(范围是[-5 , 256]),而不是所有的整型对象。需要注意的是,这仅仅在IDLE命令行中执行才是这样子的结果,如果在pycharm或者保存为文件执行时,结果是不一样的!这是因为解释器做了一系列的优化。同样的道理,字符串对象也有类似的缓存池,超过这个区间范围自然就不会相等。

总的来说,只有数值型和字符串型,并且在通用的对象池中的情况下,a is b才为True 。否则当a和b是int 、 str 、tuple 、 list 、 dict 、 set时,a is b为False

 

三、变量赋值、浅拷贝与深拷贝

A、变量赋值

在python中,都是将“对象的引用(内存地址)”赋值给变量的。

直接赋值,传递对象的引用而已,原始列表改变,被赋值的b也会做相同的改变。

  1. >>> list = [1,2,3]
  2. >>> a = list
  3. >>> print(a)
  4. [1, 2, 3]
  5. >>> list.append(4)
  6. >>> print(a)
  7. [1, 2, 3, 4]
  8. >>> x = 2
  9. >>> y = x
  10. >>> print(id(x))
  11. 140712489444208
  12. >>> print(id(y))
  13. 140712489444208
  14. >>> print(id(2))
  15. 140712489444208

在语句x = 2中,做了两件事:创建了一个整型对象;将该对象的引用(即对象的内存地址)赋值给名为x的变量,创建变量x。

注意:

(1)在python中,每个变量在使用前都必须赋值,变量是在赋值的那一刻被创建的。

(2)在 Python 中,变量就是变量,它没有类型,我们所说的"类型"是变量所指的内存中对象的类型。

有人喜欢把给变量赋值比喻成“贴标签”,把x, y这两个标签贴到2这个对象上。

 

B、浅拷贝 -- copy模块里面的copy方法实现

copy浅拷贝,没有拷贝子对象,所以原始数据改变,子对象会改变

(1)对于 不可 变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间。

(2)对于 变类型 List、Dictionary、Set,浅复制会开辟新的空间地址(仅仅是最顶层开辟了新的空间,里层的元素地址还是一样的),进行浅拷贝。

(3)浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象的;

(4)浅拷贝后,改变原始对象中为不可变类型的元素的值,只有原始类型受影响。 (操作拷贝对象对原始对象的也是同理)

  1. 可变类型跟不可变类型在浅拷贝中的区别:
  2. (1)不可变类型 数字、字符串、元组 -------地址相同!!!
  3. >>> import copy
  4. >>> num1 = 1
  5. >>> num2 = copy.copy(num1)
  6. >>> print(id(num1))
  7. 140712489444176
  8. >>> print(id(num2))
  9. 140712489444176
  10. >>> str1 = 'happy'
  11. >>> str2 = copy.copy(str1)
  12. >>> print(id(str1))
  13. 2983938062072
  14. >>> print(id(str2))
  15. 2983938062072
  16. >>> tup1 = (1,2,3,'AI')
  17. >>> tup2 = copy.copy(tup1)
  18. >>> print(id(tup1))
  19. 2983937738936
  20. >>> print(id(tup2))
  21. 2983937738936
  22. 2)可变类型 列表、字典、集合 ------ 地址不同!!!
  23. >>> import copy
  24. >>> list1 = [1,2,3]
  25. >>> list2 = copy.copy(list1)
  26. >>> print(id(list1))
  27. 2983938304456
  28. >>> print(id(list2))
  29. 2983938304840
  30. >>> dict1 = {'A':1, 'B':2}
  31. >>> dict2 = copy.copy(dict1)
  32. >>> print(id(dict1))
  33. 2983938292112
  34. >>> print(id(dict2))
  35. 2983938001800
  36. >>> set1 = {1,2}
  37. >>> set2 = copy.copy(set1)
  38. >>> print(id(set1))
  39. 2983938033928
  40. >>> print(id(set2))
  41. 2983938032808
  42. 3)注意 copy浅拷贝,没有拷贝子对象,所以原始数据改变,子对象会改变 :
  43. >>> import copy
  44. >>> alist = [1,2,3,['a','b']]
  45. >>> c = copy.copy(alist)
  46. >>> print(alist)
  47. [1, 2, 3, ['a', 'b']]
  48. >>> print(c)
  49. [1, 2, 3, ['a', 'b']]
  50. >>> alist.append(5) # 此操作不会改变浅拷贝c的值
  51. >>> print(alist)
  52. [1, 2, 3, ['a', 'b'], 5]
  53. >>> print(c)
  54. [1, 2, 3, ['a', 'b']]
  55. >>> alist[3]
  56. ['a', 'b']
  57. >>> alist[3].append('c') # 此操作会改变浅拷贝c的值
  58. >>> print(alist)
  59. [1, 2, 3, ['a', 'b', 'c'], 5]
  60. >>> print(c)
  61. [1, 2, 3, ['a', 'b', 'c']]
  62. >>> id(alist)
  63. 1426982476744
  64. >>> id(c)
  65. 1426982477128

注意:会产生浅拷贝效果的操作:

(1)切片操作

(2)使用工厂函数(如list/dir/set)

(3)使用copy模块中的copy()函数

 

C、深拷贝--copy模块里面的deepcopy方法实现

深拷贝,包含对象里面的自对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变

注意:字典自带的copy()方法可实现深拷贝

注意:在六种基本类型中,深拷贝与浅拷贝的影响几乎是一致的。因为深拷贝对比浅拷贝,强调的是递归,强调的是资源数,对于对顶层的操作,深拷贝与浅拷贝无异!

  1. 注意:深拷贝,包含对象里面的自对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
  2. >>> import copy
  3. >>> d = copy.deepcopy(alist)
  4. >>> print(alist)
  5. [1, 2, 3, ['a', 'b', 'c'], 5]
  6. >>> print(d)
  7. [1, 2, 3, ['a', 'b', 'c'], 5]
  8. >>> alist.append(6) # 不会对深拷贝的d造成影响
  9. >>> print(alist)
  10. [1, 2, 3, ['a', 'b', 'c'], 5, 6]
  11. >>> print(d)
  12. [1, 2, 3, ['a', 'b', 'c'], 5]
  13. >>> alist[3].append('d') # 不会对深拷贝的d造成影响
  14. >>> print(alist)
  15. [1, 2, 3, ['a', 'b', 'c', 'd'], 5, 6]
  16. >>> print(d)
  17. [1, 2, 3, ['a', 'b', 'c'], 5]
  18. >>> import copy
  19. >>> l1 = [1,2]
  20. >>> l2 = [3,4]
  21. >>> num = 5
  22. >>> allone = [l1,l2,num]
  23. >>> print(allone)
  24. [[1, 2], [3, 4], 5]
  25. >>> allone2 = copy.deepcopy(allone)
  26. >>> print(allone2)
  27. [[1, 2], [3, 4], 5]
  28. >>> allone[1] = [4,3]
  29. >>> allone[2] = [6,5]
  30. >>> print(allone)
  31. [[1, 2], [4, 3], [6, 5]]
  32. >>> print(allone2) # 依旧不会对深拷贝的d造成影响
  33. [[1, 2], [3, 4], 5]

 

D、python默认的拷贝方式为浅拷贝

时间角度:浅拷贝花费时间更少;

空间角度:浅拷贝花费内存更少;

效率角度:浅拷贝只拷贝顶层数据,一般情况下比深拷贝效率高。

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/332421
推荐阅读
相关标签
  

闽ICP备14008679号