python2.7中複製資料模型(可變與不可變模型)的幾個坑

weixin_34019929發表於2017-04-16

python2.7中對於不同的資料模型對於不同的複製方式會出現不一樣的結果,平時工作中遇到很多坑,總結如下。

2933324-612233805733917f.png
python的複製問題

一、不可變資料模型(整型int、浮點型float、字串型string和元組tuple)

  • 第1種:通過等號[=]複製
originalStr = 'nanjing'
anotherStr = originalStr    # [=]號複製
print '複製前後是否為同一記憶體地址: %s' % (id(originalStr) == id(anotherStr))
nowCity = 'nantong'
print '原字串: nanjing, 現字串: %s' % originalStr
---
複製前後是否為同一記憶體地址: True
原字串: nanjing, 現字串: nanjing
  • 第2種:通過工廠方法複製
originalStr = 'nanjing'
anotherStr = str(originalStr)  # 通過str()
print '複製前後是否為同一記憶體地址: %s' % (id(originalStr) == id(anotherStr))
nowCity = 'nantong'
print '原字串: nanjing, 現字串: %s' % originalStr
---
複製前後是否為同一記憶體地址: True
原字串: nanjing, 現字串: nanjing
第3種:通過淺拷貝(copy)方法複製
import copy
originalStr = 'nanjing'
anotherStr = copy.copy(originalStr)  # 淺拷貝,只拷貝頂級物件
print '複製前後是否為同一記憶體地址: %s' % (id(originalStr) == id(anotherStr))
nowCity = 'nantong'
print '原字串: nanjing, 現字串: %s' % originalStr
---
複製前後是否為同一記憶體地址: True
原字串: nanjing, 現字串: nanjing
第4種:通過深拷貝(deepcopy)方法複製
import copy
originalStr = 'nanjing'
anotherStr = copy.deepcopy(originalStr)  # 深拷貝,拷貝頂級物件及巢狀物件
print '複製前後是否為同一記憶體地址: %s' % (id(originalStr) == id(anotherStr))
nowCity = 'nantong'
print '原字串: nanjing, 現字串: %s' % originalStr
---
複製前後是否為同一記憶體地址: True
原字串: nanjing, 現字串: nanjing

二、可變資料模型列表list、字典dict

  • 第1種:通過等號[=]複製
originalList = ['nanjing', [1, 2]]
anotherList = originalList  # [=]號複製
print '複製前後是否為同一記憶體地址: %s' % (id(originalList) == id(anotherList))
anotherList[0] = 'nantong'
anotherList[1].append(3)
print "原列表: ['nanjing', [1, 2]], 現列表: %s" % originalList
--
複製前後是否為同一記憶體地址: True
原列表: ['nanjing', [1, 2]], 現列表: ['nantong', [1, 2, 3]]
  • 第2種:通過工廠方法複製
originalList = ['nanjing', [1, 2]]
anotherList = list(originalList)  # 通過list()複製
print '複製前後是否為同一記憶體地址: %s' % (id(originalList) == id(anotherList))
anotherList[0] = 'nantong'
anotherList[1].append(3)
print "原列表: ['nanjing', [1, 2]], 現列表: %s" % originalList
---
複製前後是否為同一記憶體地址: False
原列表: ['nanjing', [1, 2]], 現列表: ['nanjing', [1, 2, 3]]
  • 第3種:通過[:](值傳遞)複製
originalList = ['nanjing', [1, 2]]
anotherList = originalList[:]  # 通過[:]複製
print '複製前後是否為同一記憶體地址: %s' % (id(originalList) == id(anotherList))
anotherList[0] = 'nantong'
anotherList[1].append(3)
print "原列表: ['nanjing', [1, 2]], 現列表: %s" % originalList
---
複製前後是否為同一記憶體地址: False
原列表: ['nanjing', [1, 2]], 現列表: ['nanjing', [1, 2, 3]]
  • 第4種:通過淺拷貝(copy)方法複製
import copy
originalList = ['nanjing', [1, 2]]
anotherList = copy.copy(originalList)  # 淺拷貝,只拷貝頂級物件
print '複製前後是否為同一記憶體地址: %s' % (id(originalList) == id(anotherList))
anotherList[0] = 'nantong'
anotherList[1].append(3)
print "原列表: ['nanjing', [1, 2]], 現列表: %s" % originalList
---
複製前後是否為同一記憶體地址: False
原列表: ['nanjing', [1, 2]], 現列表: ['nanjing', [1, 2, 3]]
  • 第5種:通過深拷貝(deepcopy)方法複製
import copy
originalList = ['nanjing', [1, 2]]
anotherList = copy.deepcopy(originalList)  # 深拷貝,拷貝頂級物件及巢狀物件
print '複製前後是否為同一記憶體地址: %s' % (id(originalList) == id(anotherList))
anotherList[0] = 'nantong'
anotherList[1].append(3)
print "原列表: ['nanjing', [1, 2]], 現列表: %s" % originalList
---
複製前後是否為同一記憶體地址: False
原列表: ['nanjing', [1, 2]], 現列表: ['nanjing', [1, 2]]

初步總結

第1種:通過等號[=]複製
- 不論可變還是不可變資料型別,通過[=]複製後都指向同一個記憶體地址;
- 改變複製後的資料(例子中的anotherStr,anotherList),原資料中不可變資料模型值未改變,可變資料模型值改變
-
第2種:通過工廠方法複製
- 不可變資料模型複製後指向同一個記憶體地址,可變資料模型指向不同地址;
- 改變複製後的資料(例子中的anotherStr,anotherList),原資料中不可變資料模型值未改變,可變資料模型值改變
-
第3種:通過[:](值傳遞)複製
- 不可變資料模型不涉及;可變資料模型指向不同記憶體地址;
- 改變複製後的資料(anotherList),原資料中不可變資料模型值未改變,可變資料模型值改變
-
第4種:通過淺拷貝(copy)方法複製
- 不可變資料模型複製後指向同一個記憶體地址,可變資料模型指向不同地址;
- 改變複製後的資料(例子中的anotherStr,anotherList),原資料中不可變資料模型值未改變,可變資料模型值改變
-
第5種:通過深拷貝(deepcopy)方法複製
- 不可變資料模型複製後指向同一個記憶體地址,可變資料模型指向不同地址;
- 改變複製後的資料(例子中的anotherStr,anotherList),原資料中不可變、可變資料模型值均未改變

最終總結

- 對於不可變資料模型,不論通過什麼辦法複製,通過改變複製後的資料,均不會改變原資料的值
- 對於可變資料模型,除深拷貝不會改變原資料值,其他均會改變原資料值

相關文章