python拷贝字典
1. python对象的拷贝
Python赋值操作或函数参数传递,传递的永远是对象引用(即内存地址),而不是对象内容。在Python中一切皆对象,对象又分为可变(mutable)和不可变(immutable)两种类型。对象拷贝是指在内存中创建新的对象,产生新的内存地址。当顶层对象和它的子元素对象全都是immutable不可变对象时,不存在被拷贝,因为没有产生新对象。浅拷贝(Shallow Copy),拷贝顶层对象,但不会拷贝内部的子元素对象。深拷贝(Deep Copy),递归拷贝顶层对象,以及它内部的子元素对象。
Python中一切皆对象,对象就像一个塑料盒子, 里面装的是数据。对象有不同类型,例如布尔型和整型,类型决定了可以对它进行的操作。现实生活中的"陶器"会暗含一些信息(例如它可能很重且易碎,注意不要掉到地上)。
对象的类型还决定了它装着的数据是允许被修改的变量(可变的mutable)还是不可被修改的常量(不可变的immutable)。你可以把不可变对象想象成一个透明但封闭的盒子:你可以看到里面装的数据,但是无法改变它。类似地,可变对象就像一个开着口的盒子,你不仅可以看到里面的数据,还可以拿出来修改它,但你无法改变这个盒子本身,即你无法改变对象的类型。
对象拷贝是指在内存中创建新的对象,产生新的内存地址。
浅拷贝(Shallow Copy),拷贝顶层对象,但不会拷贝内部的子元素对象。
2.1.1. 顶层是mutable,子元素全是immutable
当顶层对象是mutable可变对象,但是它的子元素对象全都是immutable不可变对象时,如[1, 'world', 2]
① 创建列表对象并赋值给变量a
② 导入模块,使用.()函数浅拷贝a,并赋值给变量b
③ 修改变量a的子元素a[0] = 3,由于整数是不可变对象,所以并不是修改1变为3,而是更改a[0]指向对象3
当顶层对象是 mutable可变对象 ,但子元素也存在 mutable可变对象 时,如 [1, 2, ['hello','world']]
① 浅拷贝 .() 只拷贝了顶层对象,没有拷贝子元素对象['hello','world'],即a[2]和b[2]指向同一个列表对象
② 修改a[2][1] = 'china',则b[2][1] = 'china'
当顶层对象是immutable不可变对象,同时它的子元素对象也全都是immutable不可变对象时,如(1, 2, 3)
变量a与变量b指向的是同一个元组对象,没有拷贝
当顶层对象是immutable不可变对象时,但子元素存在mutable可变对象时,如(1, 2, ['hello','world'])
变量a与变量b指向的是相同的元组对象,并且a[2]与b[2]指向同一个列表,所以修改a[2][1]会影响b[2][1]
深拷贝(Deep Copy),递归拷贝顶层对象,以及它内部的子元素对象
当顶层对象是mutable可变对象,但是它的子元素对象全都是immutable不可变对象时,如[1, 'world', 2]
变量a与变量b指向不同的列表对象,修改a[0]只是将列表a的第一个元素重新指向新对象,不会影响b[0]
当顶层对象是mutable可变对象,但子元素也存在mutable可变对象时,如[1, 2, ['hello','world']]
深拷贝既拷贝了顶层对象,又递归拷贝了子元素对象,所以a[2]与b[2]指向了两个不同的列表对象(但是列表对象的子元素初始指定的字符串对象一样),修改a[2][1] = 'china'后,它重新指向了新的字符串对象(内存地址为140531581905808),不会影响到b[2][1]
当顶层对象是immutable不可变对象,同时它的子元素对象也全都是immutable不可变对象时,如(1, 2, 3)
变量a与变量b指向的是同一个元组对象,不存在拷贝
当顶层对象是immutable不可变对象时,但子元素存在mutable可变对象时,如(1, 2, ['hello','world'])
变量a与变量b指向的是不同的元组对象,同时a[2]与b[2]指向不同的列表对象,所以修改a[2][1]不会影响b[2][1]
使用=是赋值,即将列表对象的引用也赋值给变量b,可以将列表对象想象成一个盒子,变量a相当于这个盒子上的标签,执行b = a后,相当于再在这个盒子上贴上b标签,a和b实际上指向的是同一个对象。因此,无论我们是通过a还是通过b来修改列表的内容,其结果都会作用于双方。
b/c/d都是a的复制,它们都指向了不同的列表对象,但是没有拷贝子元素,a[2]和b[2]/c[2]/d[2]指向同一个列表, 相当于浅拷贝的效果
使用分片[:]操作,a和b其实是指向同一个元组,而且没有拷贝子元素,a[2]和b[2]也指向同一个列表,相当于浅拷贝的效果
同列表类似,可以使用字典的()函数或者转换函数dict()
变量a与变量b/c指向不同的字典,但是没有拷贝子元素,a['jobs']和b['jobs']/c['jobs']指定同一个列表, 相当于浅拷贝的效果
同列表类似,可以使用集合的()函数或者转换函数set()
变量a与变量b/c指向不同的集合,而集合的元素必须是hashable,所以修改集合a不会影响到b/c
2. python 函数里面 字典复制问题
如果是我,我会在函数里面声明b是global的,而不是用似是而非的传值传指针,你这样写是想说b_hash传递的是指针,可惜python里一旦用“=”赋值就已经相当于声明了一个新的变量,所以你的这个问题两种解决办法:
第一个,把你要传指针的东西放到列表里:
deftest(aa,bb):
bb[0]=.deep(aa)
a={1:1}
b=[{}]
test(a,b)
printb[0]
这样保证你可以通过b这个名字找到改变后的指针。
第二个,在函数里声明你要修改的是全局变量:
deftest(aa):
globalb
b=.deep(aa)
a={1:1}
b={}
test(a)
printb
当然,你还可以用既不是global也不是local的局部作用域,那可以说叫闭包,但有些不好懂就不说了。。。
楼上的方法思想和第一种一样,但是没做深层拷贝,一层for循环没有递归实现了.,而不是.deep。。。
3. python复制字典为什么有单引号
Python定义了字典。Python是一种跨平台的计算机程序设计语言,python复制字典有单引号是因为Python定义了字典。是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。最初被设计用于编写自动化脚本,随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。
4. python字典浅复制问题
这个情况跟你设计有关系的,dict1['1']应该是一个list,然后dict2['1']是另外一个list。如果前面的list跟后面的list不是一个,或者没有的关系的话,修改dict1['1']不会影响dict2['1']。
如果dict1['1'][0]是一个list,然后dict2['1'][0]也指向这个list的话,修改dict1['1'][0],dict2['1'][0]也会跟着变化。
5. python字典浅复制问题
浅复制只复制对象内存,dict1的内存里放了两个引用list1和list2分别指向两个列表对象x和y,将dict1的内存复制到dict2中,于是dict2中也有两个引用list3和list4分别指向两个列表对象x和y。list1和list3指向同一个列表对象x,而list2和list4指向同一个列表对象y。通过list1去修改列表对象x的内容,再通过list3去访问,结果当然是一致变化的。
6. python dict用法
dic= {key1 : value1, key2 : value2 }
字典也被称作关联数组或哈希表。下面是几种常见的字典属性:
1、dict.clear()
clear() 用于清空字典中所有元素(键-值对),对一个字典执行 clear() 方法之后,该字典就会变成一个空字典。
2、dict.()
() 用于返回一个字典的浅拷贝。
3、dict.fromkeys()
fromkeys() 使用给定的多个键创建一个新字典,值默认都是 None,也可以传入一个参数作为默认的值。
4、dict.get()
get() 用于返回指定键的值,也就是根据键来获取值,在键不存在的情况下,返回 None,也可以指定返回值。
5、dict.items()
items() 获取字典中的所有键-值对,一般情况下可以将结果转化为列表再进行后续处理。
6、dict.keys()
keys() 返回一个字典所有的键。
7. Python字典创建、基本操作以及常用方法
创建一个空字典自需要一对大括号即可,从已有的键-值对映射或关键字参数创建字典需要使用 dict 函数(类)
把一个列表转为字典,列表的每一项都是长度为2的序列。
还可使用 关键字实参 (**kwargs)来调用这个函数,如下所示:
字典的基本操作与序列十分相似:
字典与序列的不同:
方法 clear 删除所有的字典项(key-value)。
复制,得到原字典的一个新副本。
效果等同于调用 dict(d) 创建新字典。
() 执行的是 浅复制 ,若字典的值是一个可变对象,那么复制以后,相同一个键将关联到同一个对象,修改该对象,将同时修改两个字典。
模块中的函数deep 可执行深复制。
方法fromkeys 创建一个新字典,其中包含指定的键,且每个键对应的值都是None,或者可以提供一个i额默认值。
方法get 为访问字典项提供了宽松的环境。通常,如果你试图访问字典中没有的项,将引发错误,而get直接返回None,或者可设置默认返回值。
当字典中不存在指定键时, setdefault(k,v) 添加一个指定键-值对;且返回指定键所关联的值。
这三个方法返回值属于一种名为 字典视图 的特殊类型。字典视图可用于迭代。另外,还可确定其长度以及对其执行成员资格检查。
这三个方法自大的特点是不可变,当你的接口试图对其他用户提供一个只读字典,而不希望他们修改的时候,这三个方法是很有用的;而且当原字典发生改变时,这些方法返回的对象也会跟着改变。
方法 pop 可用于获取与指定键相关联的值,并将该键-值对从字典中删除。
popitem随机删除一个键-值对,并返回一个二维的元组 (key, value) ,因为字典是无序的,所以其弹出的顺序也是不确定的。
书上说,这个方法在大数据量时执行效率很高,但没有亲测。
方法update 使用一个字典中的项来更新另一个字典。
8. python字典的基本操作
python字典的基本操作如下:
查询字典
字典里面可以嵌套字典,嵌套列表。
9. Python3 & 浅拷贝与深拷贝
在Python中对象的赋值(=)其实就是对象的引用。即:当创建一个对象,把它赋值给另一个变量时,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已。
Python中对象的拷贝分为:浅拷贝()和深拷贝(deep)。
浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。也就是,将原对象在内存中引用地址拷贝过来,然后让新的对象指向这个地址。可以使用“=”或列表自带的()函数(如list.()),或使用模块的()函数。
深拷贝:外围和内部元素都进行了拷贝对象本身,而不是引用。即把对象复制一遍,并且该对象中引用的其他对象也同时复制,完全得到一个新的一模一样的对象,对新对象里的值进行修改不会影响原有对象,新对象和原对象完全分离开。深拷贝只能使用模块中deep()函数,使用前要导入:from import deep。
Python中对象分为不可变对象 、可变对象。
不可变对象:一旦创建就不可修改的对象,例如:字符串、元组、数字
可变对象:可以修改的对象,例如:列表、字典。
其中Python中的切片可以应用于:列表、元组、字符串,但不能应用于字典。
而深浅拷贝,可应用于序列(列表、元组、字符串),也可应用于字典。
其中不可变对象,不管是深拷贝还是浅拷贝,地址值在拷贝后的值都是一样的。
以下以元组(不可变类型)为例
从上述示例可以看出:
不可变对象类型,没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。
所以不可变类型,不管是深拷贝还是浅拷贝,地址值和拷贝后的值都是一样的。
以下以列表(可变类型)为例
第一种方法:使用=号浅拷贝
输出结果:
第二种方法:使用浅拷贝
输出结果:
第三种方法:使用deep深拷贝
输出结果:
从上述示例可以看出:
=浅拷贝:值相等,地址相等
浅拷贝:值相等,地址不相等
deep深拷贝:值相等,地址不相等
总结:
1,深浅拷贝都是对源对象的复制,占用不同的内存空间。
2,不可变类型的对象,对于深浅拷贝毫无影响,最终的地址值和值都是相等的。
3,可变类型的对象,使用=浅拷贝时, 值相等,地址相等,对新对象里的值进行修改同时会影响原有对象;使用浅拷贝时值相等,地址不相等;使用deep深拷贝时值相等,地址不相等。可以看出针对可变类型浅拷贝和deep深拷贝,对新对象里的值进行修改不会影响原有对象。
10. python深拷贝和浅拷贝的区别
浅拷贝是对一个对象父级(外层)的拷贝,并不会拷贝子级(内部),而深拷贝对一个对象是所有层次的拷贝(递归),内部和外部都会被拷贝过来。
使用浅拷贝的时候,分为两种情况。
第一种,如果最外层的数据类型是可变的,比如说列表,字典等,浅拷贝会开启新的地址空间去存放。