1.Python浅复制和深复制——copy和deepcopy方法_kakahub的博客-程序员宅基地

技术标签: Python  

【Python百知百问】1.Python浅复制和深复制——copy和deepcopy方法

问题:Python里面如何拷贝一个对象?

 

 

参考:《Python Cookbook》

 

参考链接:http://blog.csdn.net/sharkw/article/details/1934090 

 

 

方法说明:

copy(x)

    Shallow copy operation on arbitrary Python objects.

 

    See the module's __doc__ string for more info. 

 

deepcopy(x, memo=None, _nil=[])

    Deep copy operation on arbitrary Python objects.

 

    See the module's __doc__ string for more info. 

 

标准库中的copy模块提供了两个方法来实现拷贝.一个方法是copy,它返回和参数包含内容一样的对象.

 

import copy

new_list = copy.copy(existing_list)

 

有些时候,你希望对象中的属性也被复制,可以使用deepcopy方法:

 

import copy

new_list_of_dicts = copy.deepcopy(existing_list_of_dicts)

 

当你对一个对象赋值的时候(做为参数传递,或者做为返回值),Python和Java一样,总是传递原始对象的引用,而不是一个副本.其它一些语言当赋值的时候总是传递副本.Python从不猜测用户的需求 ,如果你想要一个副本,你必须显式的要求.

Python的行为很简单,迅速,而且一致.然而,如果你需要一个对象拷贝而并没有显式的写出来,会出现问题的,比如:

>>> a = [1, 2, 3]

>>> b = a

>>> b.append(5)

>>> print a, b 

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

 

在这里,变量a和b都指向同一个对象(一个列表),所以,一旦你修改了二者之一,另外一个也会受到影响.无论怎样,都会修改原来的对象.

注意:

要想成为一个Python高手,首先要注意的问题就是对象的变更操作和赋值,它们都是针对对象的引用操作的.一个语句比如a = []将a重新绑定给一个新对象,但不会影响以前的对象.然而,对象复制却不同,当对象复制后,对象变更操作就有了区别. 

如 果你想修改一个对象,而且想让原始的对象不受影响,那你就需要对象复制.正如本节说的一样,你可以使用copy模块中的两个方法来实现需求.一般的,可以 使用copy.copy,它可以进行对象的浅复制(shallow copy),它复制了对象,但对于对象中的元素,依然使用引用.

浅复制,有时无法获得一个和原来对象完全一致的副本,如果你想修改对象中的元素,不仅仅是对象本身的话:

 

>>> list_of_lists = [ ['a'], [1, 2], ['z', 23] ]

>>> copy_lol = copy.copy(lists_of_lists) 

>>> copy_lol[1].append('boo') 

>>> print list_of_lists, copy_lol 

[['a'], [1, 2, 'boo'], ['z', 23]] [['a'], [1, 2, 'boo'], ['z', 23]] 

 

在这里,变量list_of_lists,copy_lol指向了两个不同的对象,所以我们可以修改它们任何一个, 而不影响另外一个.然而,如果我们修改了一个对象中的元素,那么另一个也会受影响,因为它们中的元素还是共享引用.

如果你希望复制一个容器对象,以及它里面的所有元素(包含元素的子元素),使用copy.deepcopy,这个方法会消耗一些时间和空间,不过,如果你需要完全复制,这是唯一的方法.

对于一般的浅拷贝,使用copy.copy就可以了,当然,你需要了解你要拷贝的对象.要复制列表L,使用list(L),要复制一个字典d,使用dict(d),要复制一个集合s,使用set(s),这样,我们总结出一个规律,如果你要复制一个对象o,它属于内建的类型t,那么你可以使用t(o)来 获得一个拷贝.dict也提供了一个复制版本,dict.copy,这个和dict(d)是一样,我推荐你使用后者,这个使得代码更一致,而且还少几个字符.

要复制一个别的类型,无论是你自己写的还是使用库中的,使用copy.copy,如果你自己写一个类,没有必要费神去写clone和copy函数,如果你想定义自己的类复制的方式,实现一个__copy__,或者__getstate__和__setstate__.如果你想定义自己类型的deepcopy,实现方法__deepcopy__. 

注意你不用复制不可修改对象(string,数字,元组),因为你不用担心修改它们.如果你想尝试一下复制,依然会得到原来的.虽然无伤大雅,不过真的浪费尽力:

 

>>> s = 'cat' 

>>> t = copy.copy(s) 

>>> s is t 

True

 

is操作符用于不仅判断两个对象是否完全一致,而且是同一个对象(is判断标识符,要比较内容,使用==),判断标识符是否相等对于不可修改对象没有什么意义.然而 ,判断标识符对于可修改对象有时候是很重要的,比如,你不确定a和b是否指向同一个对象,使用a is b会立刻得到结果.这样你可以自己判断是否需要使用对象拷贝.

注意:

你可以使用另一种拷贝方式,给定一个列表L,无论是完整切片L[:]或者列表解析[x for x in L],都会获得L的浅拷贝,试试L+[],L*1...但是上面两种方法都会使人迷惑,使用list(L)最清晰和快速,当然,由于历史原因,你可能会经常看到L[:]的写法. 

对于dict,你可能见过下面的复制方法:

>>> for somekey in d: 

... d1[somekey] = d[somekey]

 

或者更简单一些的方法,d1={},d1.update(d),无论怎样,这些代码都是缺乏效率的,使用d1=dict(d)吧.

 

 

 

总结:

1.浅复制 :  使用copy.copy,它可以进行对象的浅复制(shallow copy),它复制了对象,但对于对象中的元素,依然使用引用.

2.深复制 :  使用copy.deepcopy,它可以进行深复制,不仅复制了对象,同时也复制了对象中的元素,但这需要牺牲一定的时间和空间。

3.要复制列表L,使用list(L),要复制一个字典d,使用dict(d),要复制一个集合s,使用set(s),这样,我们总结出一个规律,如果你要复制一个对象o,它属于内建的类型t,那么你可以使用t(o)来 获得一个拷贝.dict也提供了一个复制版本,dict.copy。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u014615166/article/details/68072287

智能推荐

FTP(S) 通信之旅—基于SIM820X和SIM7600X-程序员宅基地

record and play of wavefile1) Record a wav audio,named rec.wav in e disk[14:20:59.276]IN←◆AT+CREC=1,"e:/rec.wav"[14:20:59.381]IN←◆+CREC: 1OK2) Stop recording above[14:23:06.304]OUT→◇AT+CREC=0□[14:23:06.308]IN←◆AT+CREC=0+CREC: 0OKti...

控制用计算机的硬件结构图,软考程序员教程重点精讲之计算机系统的硬件组成...-程序员宅基地

软考程序员考试属于计算机软件水平考试(简称软考)中的一个初级计算机职称考试。对于软考程序员考试并无学历及资历条件限制,更无论年龄、专业与资历。一年可报考软考程序员考试两次,但一次考试只能报考一种资格,因此报考了程序员考试则无法再报考软考其他级别或科目的考试。同时软考程序员考试采用笔试形式,考试实行全国统一大纲、统一试题、统一时间、统一标准、统一证书的考试方式。下面的小编给大家提供的软考程序员教程重..._计算机硬件系统的构图

使用报表模型设计报表时,如何正确设置筛选条件?-程序员宅基地

使用报表模型来设计报表的时候,我们可能会用到一些条件筛选,和直接使用存储过程来查询相比,还是有点儿区别的,使用存储过程或者查询语句的话,我们可以通过设置一些变量参数"@Id”等,然后在数据集的参数选项中,添加相应的变量对应关系,如: "@Id=Parameters!Id.Value" 这样即可将报表页面中的条件和我们查询语句或存储过程中的条件...

js charCodeAt_ charAt.html_html charcodeat-程序员宅基地

<!doctype html><html lang="en"><head> <meta charset="UTF-8"> <title>charCodeAt_ charAt</title></head><body><script> /*定义和用法 ..._html charcodeat

添加组员昵称_https://blog.csdn.net/qq_44109821/article/details/-程序员宅基地

<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>组员昵称</title> </head> <body> <label for="">请输入组员昵称:</label><input typ..._https://blog.csdn.net/qq_44109821/article/details/103632823

随便推点

c语言含参数字符串,在C语言中模拟含有默认参数的函数-程序员宅基地

【好久没写了,来篇技术科普文】写C++代码的时候总想当然以为C中也有含默认参数的函数这种玩意儿(值得注意的是Java也不支持而C#支持,Scala这种奇葩支持是不足为奇的),然后在编译下面这段代码之后颜面扫尽TwT#include "default_args.h"void printString(const char* msg,int size,int style){printf("%s %d %..._含参数的字符串

Python刷leetcode106. 从中序与后序遍历序列构造二叉树_leetcode从中序与后序遍历序列构造二叉树 python-程序员宅基地

根据一棵树的中序遍历与后序遍历构造二叉树。注意:你可以假设树中没有重复的元素。例如,给出中序遍历 inorder = [9,3,15,20,7]后序遍历 postorder = [9,15,7,20,3]返回如下的二叉树: 3 / \ 9 20 / \ 15 7思路:与上一篇基本相同,找到中序和后序的对应关系,中序为【左,根,右】,后序为【左,右,根】# ..._leetcode从中序与后序遍历序列构造二叉树 python

短进程优先调度算法c语言spf,操作系统:C++实现SJF(短作业优先调度算法)_drtzp的博客-程序员宅基地

算法描述:短作业(进程)优先调度算法(SJF),是指对短作业或短进程优先调度的算法。它们可以分 别用于作业调度和进程调度。短作业优先(SJF)的调度算法是从后备队列中选择一个或若干个 估计运行时间最短的作业,将它们调入内存运行。而短进程优先(SPF)调度算法则是从就绪队 列中选出一个估计运行时间最短的进程,将处理机分配给它,使它立即执行并一直执行到完 成,或发生某事件而被阻塞放弃处理机时再重新调度..._什么是短进程调度算法

matlab阵风仿真,基于matlab风力发电系统的建模与仿真毕业设计论文_于人士心的博客-程序员宅基地

《基于matlab风力发电系统的建模与仿真毕业设计论文.doc》由会员分享,可免费在线阅读全文,更多与《基于matlab风力发电系统的建模与仿真毕业设计论文》相关文档资源请在帮帮文库(www.woc88.com)数亿文档库存里搜索。1、的风力发电系统仿真研究[J]中国电力教育,年研究综述与技术论坛专刊,:]王聪,刘永前风力发电系统的建模与仿真研究[J]中国电力教育,年研究综述与技术论坛专刊,:[]..._matlab在风力发电技术中的应用文献资料

POJ 2299(树状数组求逆序对)-程序员宅基地

Ultra-QuickSortTime Limit: 7000MS Memory Limit: 65536KTotal Submissions: 62722 Accepted: 23367DescriptionIn this problem, you have to analyze a particular sorting

【java办公自动化(9)】-- windows加黄金拍档spleeter,完美分离抖音网红歌曲人声和背景声_spleeter java-程序员宅基地

【java办公自动化(9)】-- windows加黄金拍档spleeter,完美分离抖音网红歌曲人声和背景声前言:最近看哔哩哔哩,发现网上很多音乐鬼才,鬼畜由此而生。也无聊在家刷抖音,其中歌曲余音绕梁,这里爬取抖音视频就不教了,但是歌曲中的背景声尤其喜欢,但五音不全的我,分不清音准的高低,也不会使用专业软件,上网查了下,像白纸的小白白可以零基础使用spleeter,虽说spleeter官网表明..._spleeter java

推荐文章

热门文章

相关标签