1.列表拷贝

引用是指保存的值为对象的地址。在 Python 语言中,一个变量保存的值除了基本类型保存的是值外,其它都是引用,因此对于它们的使用就需要小心一些。下面举个例子:

问题描述:已知一个列表,求生成一个新的列表,列表元素是原列表的复制

a=[1,2]
b=a

这种做法其实并未真正生成一个新的列表,b指向的仍然是a所指向的对象。这样,如果对a或b的元素进行修改,a,b的值同时发生变化。

解决的方法为:

a=[1,2]
b=a[:]

这样修改a对b没有影响。修改b对a没有影响。

但 这种方法只适用于简单列表,也就是列表中的元素都是基本类型,如果列表元素还存在列表的话,这种方法就不适用了。原因就是,象a[:]这种处理,只是将列 表元素的值生成一个新的列表,如果列表元素也是一个列表,如:a=[1,[2]],那么这种复制对于元素[2]的处理只是复制[2]的引用,而并未生成 [2]的一个新的列表复制。为了证明这一点,测试步骤如下:

>>> a=[1,[2]]
>>> b=a[:]
>>> b
[1, [2]]
>>> a[1].append(3)
>>> a
[1, [2, 3]]
>>> b
[1, [2, 3]]

可见,对a的修改影响到了b。如果解决这一问题,可以使用copy模块中的deepcopy函数。修改测试如下:

>>> import copy
>>> a=[1,[2]]
>>> b=copy.deepcopy(a)
>>> b
[1, [2]]
>>> a[1].append(3)
>>> a
[1, [2, 3]]
>>> b
[1, [2]]

2.字典拷贝

python 中有两种方式可以实现将一个变量的值传递给另一个变量。
一种是使用‘=’直接赋值。另一种是使用函数 copy();例如:

>>> d = {'a':'a','b':'b'}
>>> e = d.copy()
>>> f = d
>>> print (e,f)
{'b': 'b', 'a': 'a'} {'b': 'b', 'a': 'a'}

那么它们的效率又如何呢?我们再来看一下:

 import time
d = {'a':'a','b':'b'}
start = time.time()
g = d.copy()
end = time.time()
print (end-start)
==>31.8900001049
start = time.time()
h = d
end = time.time()
print (end-start)
==>19.125

我们发现使用‘=’直接赋值会比使用copy()函数快很多。为什么会这样呢?这是因为使用‘=’就等于是直接把这个d变量的引用地址赋给了h,也就是d和h两个变量都同时指向同一个存储地址,因此这种方式非常的快。而copy()呢,它不仅拷贝了d的值,而且拷贝了d的存储地址,也就是说d和g指向的是不同的存储地址。

如下代码所示:

>>> b['a']['b'] = 'm'
>>> b
{'b': 'b', 'a': {'b': 'm', 'a': 'a'}}
>>> a
{'b': 'b', 'a': {'b': 'm', 'a': 'a'}}
>>> a = {'c':{'d':'d','e':'e'},'f':'f'}
>>> b = a.copy()
>>> a['f'] = 'qq'
>>> print(a , b)
{'c': {'d': 'd', 'e': 'e'}, 'f': 'qq'} {'c': {'d': 'd', 'e': 'e'}, 'f': 'f'}
>>> a['c']['e'] = 'mm'
>>> print(a , b)
{'c': {'d': 'd', 'e': 'mm'}, 'f': 'qq'} {'c': {'d': 'd', 'e': 'mm'}, 'f': 'f'}

字典的copy也是浅拷贝,如同list的拷贝原理相同,要实现深拷贝,使用deepcopy(),代码如下所示:

>>> import copy
>>> a = {'c':{'d':'d','e':'e'},'f':'f'}
>>> b = copy.copy(a)
>>> c = copy.deepcopy(a)
>>> a['c']['e'] = 'mm'
>>> print(a , b)
{'c': {'d': 'd', 'e': 'mm'}, 'f': 'f'} {'c': {'d': 'd', 'e': 'mm'}, 'f': 'f'}
>>> print(c)
{'c': {'d': 'd', 'e': 'e'}, 'f': 'f'}

3.字典拷贝遇到的问题示例:

import copy

def test(a_hash,b_hash):
b_hash = copy.deepcopy(a_hash)
print(b_hash) a = {}
b = {}
a[1] = 1 test(a, b)
print(b)
==>
b_hash : {1: 1}
b : {}

在该程序中,为什么得到的b是空呢?

在函数里面声明b是global的,而不是用似是而非的传值传指针,这样写是想说b_hash传递的是指针,可惜python里一旦用“=”赋值就已经相当于声明了一个新的变量,所以你的这个问题两种解决办法:

方法一:在函数里声明你要修改的是全局变量
def test(a_hash):
global b
b = copy.deepcopy(a_hash)
print("b : ",b) a = {}
b = {}
a[1] = 1 test(a)
print("b : ",b)
==>
b : {1: 1}
b : {1: 1}
方法二:把要传指针的东西放到列表里
import copy def test(a_hash, b):
b[0] = copy.deepcopy(a_hash)
print("b[0] : ",b[0]) a = {}
b = [{}]
a[1] = 1 test(a , b)
print("b : ",b)
==>
b[0] : {1: 1}
b : [{1: 1}]

4.对象拷贝

import copy
class Foo:
val = 1
ch = "hhk"
a = [1, [2, 3]] foo = Foo() cpy_foo = copy.copy(foo)
print("foo : ",foo)
print("cpy_foo : ",cpy_foo)
==>
foo : <__main__.Foo object at 0x010183D0>
cpy_foo : <__main__.Foo object at 0x0101EA10> cpy_foo.val = 1000
print(cpy_foo.val)
print(foo.val)
==>
1000
1 cpy_foo.ch = "yes"
print(cpy_foo.ch)
print(foo.ch)
==>
yes
hhk cpy_foo.a[0] = 100
print(cpy_foo.a)
print(foo.a)
==>
[100, [2, 3]]
[100, [2, 3]] cpy_foo.a[1][0] = 100
print(cpy_foo.a)
print(foo.a)
==>
[100, [100, 3]]
[100, [100, 3]]
 
print(id(foo.a), id(cpy_foo.a))

 ==>  12744224  12744224

以上的代码中,对自定义对象进行拷贝,只能拷贝简单的类型,而对于list类型,不是拷贝,而是引用。

由print(id(foo.a), id(cpy_foo.a))输出结果可知,foo对象和cpy_foo中的对象的lis在同一地址处。

将上述代码中cpy_foo = copy.copy(foo) 改为 cpy_foo = copy.deepcopy(foo) 这两个对象中lis仍然在同一地址处,这说明自定义对象的list列表不能进行深拷贝。

这是why???  有哪位大神清楚的请告知,谢谢~

Python 关于拷贝(copy)汇总(列表拷贝 // 字典拷贝 // 自定义对象拷贝)的更多相关文章

  1. python学习之路04——列表和字典

    列表和字典 python中的可变数据类型有:列表和字典 不可变类型:数字,字符串,元组 今天先讲列表和字典 一.列表 1.概念: 变量:使用变量存储数据,但是,变量存储数据每次只能存储一个数据 问题: ...

  2. Python基础(二) —— 字符串、列表、字典等常用操作

    一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. 二.三元运算 result = 值1 if 条件 else 值2 如果条件为真:result = 值1如果条件为 ...

  3. 15、python学习手册之:列表和字典

    1.列表属于可变序列,支持在原处的修改 2.在标准python解锁器内部,列表就是C数组而不是链接结构 3.内置函数map对序列中的各项应用一个函数并把结果收集到一个新的列表中 eg:list(map ...

  4. Python 函数递归-三元表达式-列表生成式-字典生成式-匿名函数-内置函数

    上节课复习: 1. 无参装饰器 def 装饰器名字(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res ...

  5. iOS 深拷贝、浅拷贝、自定义对象拷贝简介

    copy语法的目的:改变副本的时候,不会影响到源对象: 深拷贝:内容拷贝,会产生新的对象.新对象计数器置为1,源对象计数器不变. 浅拷贝:指针拷贝,不会产生新的对象.源对象计数器+1. 拷贝有下面两个 ...

  6. Python入门(二)列表、字典、字符串、元组、集合

    列表list什么是列表:Python内置的一种数据类型是列表,list是一种有序的集合,可以随时添加和删除其中的元素 创建List列表的方法 L = ['杨俊辰',‘啦啦啦’,'Tom'] empty ...

  7. Python基础(2)——列表、字典、数据运算

    1.列表 #创建列表 name_list = ['alex', 'seven', 'eric'] #或 name_list = list(['alex', 'seven', 'eric']) #访问列 ...

  8. (引用)Python 元素、元组、列表、字典的区别

    转载:http://www.th7.cn/Program/Python/201407/231060.shtml 元素: 元组:tuple=('nice','to','meet','you') 列表:l ...

  9. Python中元祖,列表,字典的区别

    Python中有3种內建的数据结构:列表.元祖和字典: 1.列表 list是处理一组有序项目的数据结构,即你可以在一个列表中存储一个序列的项目. 列表中的项目应该包括在方括号中,这样Python就知道 ...

随机推荐

  1. thinkphp5 隐藏入口和支持pathinfo

    url里public目录的隐藏 其实正常思路的话这个url里的public本身就是不存在的,然后呢,其实也不叫隐藏public目录,这里只是考虑到有些童鞋可能还会按之前3.x时代的习惯来配置网站根目录 ...

  2. 浅述Try {} Catch{} 作用

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Test ...

  3. [C/C++] C++类对象创建问题

    CSomething a();// 没有创建对象,这里不是使用默认构造函数,而是定义了一个函数,在C++ Primer393页中有说明. CSomething b(2);//使用一个参数的构造函数,创 ...

  4. BZOJ 1042 硬币购物(背包DP+容斥原理)

    可以看出这是个多重背包,运用单调队列优化可以使每次询问达到O(s).这样总复杂度为O(s*tot). 会TLE. 因为改题的特殊性,每个硬币的币值是不变的,变的只是每次询问的硬币个数. 我们不妨不考虑 ...

  5. 【bzoj1212】[HNOI2004]L语言 AC自动机

    题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...

  6. 51nod 1385凑数字(字符串+构造)

    题目大意: 给定一个n,要求找出一个最短的字符串S,使得所有1到n的整数都是S的子序列. 比如n=10,那么S=”1234056789”的时候,是满足条件的.这个时候S的长度是10. 现在给出一个n, ...

  7. 关于__name__=='__main__

    if __name__=='__main__' :  为了区分你是主动执行这个脚本,还是从别的地方把它当做一个模块去调用. 如果是主动执行,则执行.如果是调用的,则不执行主体. 里面存放的可能是一些测 ...

  8. powerdesigner 点击preview 语句出现 if exists

    drop table if exists XXX 这个是sql server 写法.如果要切换为 Oracle 写法 菜单栏: database-->change curren DBMS 选择你 ...

  9. 【题解】51nod 1806 wangyurzee的树

    看这道题目懵逼了好久, \(m <= 17\) 一眼容斥,然而并没有想到怎么求出生成树的个数.然后灵光一闪——我不是学过一个叫Prüfer编码的东西嘛?!那就完美解决啦~ Prüfer编码就是将 ...

  10. POJ1743:Musical Theme——题解

    http://poj.org/problem?id=1743 给一段数,求最大相似子串长度,如果没有输出0. 相似子串定义: 1.两个不重叠的子串,其中一个是另一个加/减一个数得来的. 2.长度> ...