浅谈Python3.6版本的几种拷贝方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Amio_/article/details/78539574

博文章节


本机环境介绍

编码语言(Python)

(py3env) C:\Users\XXX\iCloudDrive\PycharmProjects\SAT>python -V
Python 3.6.2

什么是“不可变/可变数据类型”

Python:一切皆为对象,一切皆为对象的引用. 通俗的讲有以下区别:

  • 不可变数据类型(int string float tuple)
    不允许变量的值发生改变,如果改变了变量的值,相当于是新建了一个对象。而对于相同的值的对象,在内存中则只有一个对象,内部会有一个引用计数来记录有多少个变量引用这个对象。
  • 可变数据模型(list dict)
    允许变量的值发生变化,即如果对变量进行append、+=等这种操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象,即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象。

通过等号“=”拷贝

  • 不可变数据类型
# -*- coding: utf-8 -*-

if __name__ == '__main__':
    originalStr = 'nanjing'
    anotherStr = originalStr
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalStr), id(anotherStr)))
    originalStr = 'beijing'
    print('修改后的内存地址ID为: {}'.format(id(originalStr)))
    print('原字符串: nanjing, 现字符串: {}'.format(originalStr))
---
复制前后的内存地址ID为: 36106056, 36106056
修改后的内存地址ID为: 36106112
原字符串: nanjing, 现字符串: beijing
  • 可变数据类型
# -*- coding: utf-8 -*-

if __name__ == '__main__':
    originalList = ['nanjing', [1, 2]]
    anotherList = originalList
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalList), id(anotherList)))
    originalList[0] = 'beijing'
    originalList[1].append(3)
    print('修改后的内存地址ID为: {}'.format(id(originalList)))
    print("原列表: ['nanjing', [1, 2]], 现列表: {}".format(originalList))
---
复制前后的内存地址ID为: 44647176, 44647176
修改后的内存地址ID为: 44647176
原列表: ['nanjing', [1, 2]], 现列表: ['beijing', [1, 2, 3]]

通过工厂方法拷贝

  • 不可变数据类型
# -*- coding: utf-8 -*-

if __name__ == '__main__':
    originalStr = 'nanjing'
    anotherStr = str(originalStr)
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalStr), id(anotherStr)))
    originalStr = 'beijing'
    print('修改后的内存地址ID为: {}'.format(id(originalStr)))
    print("原字符串: nanjing, 现字符串: {}".format(originalStr))
---
复制前后的内存地址ID为: 35909448, 35909448
修改后的内存地址ID为: 35909504
原字符串: nanjing, 现字符串: beijing
  • 可变数据类型
# -*- coding: utf-8 -*-

if __name__ == '__main__':
    originalList = ['nanjing', [1, 2]]
    anotherList = list(originalList)
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalList), id(anotherList)))
    originalList[0] = 'beijing'
    originalList[1].append(3)
    print('修改后的内存地址ID为: {}'.format(id(originalList)))
    print("原列表: ['nanjing', [1, 2]], 现列表: {}".format(originalList))
---
复制前后的内存地址ID为: 38290184, 44809224
修改后的内存地址ID为: 38290184
原列表: ['nanjing', [1, 2]], 现列表: ['beijing', [1, 2, 3]]

通过”:”(值传递)拷贝

  • 不可变数据类型(不涉及)

  • 可变数据类型

# -*- coding: utf-8 -*-

if __name__ == '__main__':
    originalList = ['nanjing', [1, 2]]
    anotherList = originalList[:]
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalList), id(anotherList)))
    originalList[0] = 'beijing'
    originalList[1].append(3)
    print('修改后的内存地址ID为: {}'.format(id(originalList)))
    print("原列表: ['nanjing', [1, 2]], 现列表: {}".format(originalList))
---
复制前后的内存地址ID为: 44843784, 44973640
修改后的内存地址ID为: 44843784
原列表: ['nanjing', [1, 2]], 现列表: ['beijing', [1, 2, 3]]

通过浅拷贝(copy)方法拷贝

  • 不可变数据类型
# -*- coding: utf-8 -*-
import copy

if __name__ == '__main__':
    originalStr = 'nanjing'
    anotherStr = copy.copy(originalStr)
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalStr), id(anotherStr)))
    originalStr = 'beijing'
    print('修改后的内存地址ID为: {}'.format(id(originalStr)))
    print("原字符串: nanjing, 现字符串: {}".format(originalStr))
---
复制前后的内存地址ID为: 32042824, 32042824
修改后的内存地址ID为: 32042880
原字符串: nanjing, 现字符串: beijing
  • 可变数据类型
# -*- coding: utf-8 -*-
import copy

if __name__ == '__main__':
    originalList = ['nanjing', [1, 2]]
    anotherList = copy.copy(originalList)
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalList), id(anotherList)))
    originalList[0] = 'beijing'
    originalList[1].append(3)
    print('修改后的内存地址ID为: {}'.format(id(originalList)))
    print("原列表: ['nanjing', [1, 2]], 现列表: {}".format(originalList))
---
复制前后的内存地址ID为: 45103688, 45102984
修改后的内存地址ID为: 45103688
原列表: ['nanjing', [1, 2]], 现列表: ['beijing', [1, 2, 3]]

通过深拷贝(deepcopy)方法拷贝

  • 不可变数据类型
# -*- coding: utf-8 -*-
import copy

if __name__ == '__main__':
    originalStr = 'nanjing'
    anotherStr = copy.deepcopy(originalStr)
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalStr), id(anotherStr)))
    originalStr = 'beijing'
    print('修改后的内存地址ID为: {}'.format(id(originalStr)))
    print("原字符串: nanjing, 现字符串: {}".format(originalStr))
----
复制前后的内存地址ID为: 32370504, 32370504
修改后的内存地址ID为: 32370560
原字符串: nanjing, 现字符串: beijing
  • 可变数据类型
# -*- coding: utf-8 -*-
import copy

if __name__ == '__main__':
    originalList = ['nanjing', [1, 2]]
    anotherList = copy.deepcopy(originalList)
    print('复制前后的内存地址ID为: {}, {}'.format(id(originalList), id(anotherList)))
    originalList[0] = 'beijing'
    originalList[1].append(3)
    print('修改后的内存地址ID为: {}'.format(id(originalList)))
    print("原列表: ['nanjing', [1, 2]], 现列表: {}".format(originalList))
---
复制前后的内存地址ID为: 37632584, 37631880
修改后的内存地址ID为: 37632584
原列表: ['nanjing', [1, 2]], 现列表: ['beijing', [1, 2, 3]]

最后总结

  • 通过等号拷贝:可变/不可变数据类型内存地址相同
  • 通过工厂方法拷贝:不可变数据类型内存地址相同,可变数据类型内存地址不同
  • 通过值传递拷贝:不可变数据类型不涉及,可变数据类型内存地址不同
  • 通过浅拷贝方法拷贝:不可变数据类型内存地址相同,可变数据类型内存地址不同
  • 通过深拷贝方法拷贝:不可变数据类型内存地址相同,可变数据类型内存地址不同


不可变数据类型,不论什么方式拷贝,内存地址都相同;
可变数据类型,除等号拷贝,内存地址都不同;
不可变数据类型,修改值后,内存地址改变;
可变数据类型,修改值后,内存地址不改变;

猜你喜欢

转载自blog.csdn.net/Amio_/article/details/78539574