python的一切变量都是对象,变量的存储采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的本身。
基于内存地址的分类
Python中的数据类型基于内存地址分类可以分为:
可变类型: 列表,字典,集合
不可变类型:数字,字符串,元组
这里的可变不可变,是指当该数据类型的对应变量的值发生了改变,那么它对应的内存地址是否发生改变
-
对于不可变类型
变量的每一次初始化,都开辟了一个新的内存空间,同时将新内容的地址赋值给变量。
要注意的是,即使变量对应的地址发生改变,但旧地址的内容其实并没有被修改,仍在内存中,我们可以通过引入ctypes模块读取地址的内
-
对于可变类型
当对该数据类型中的元素进行一些增删改操作的时候,不会影响到该变量本身的地址,只会改变其内部元素的地址引用。
当然,如果对其重新初始化(赋值)的时候,就给该变量重新赋予了一个新的内存地址。
赋值
结合上面对于可变、不可变数据类型的地址存储及其地址变化的理解,我们再来讨论Python中对变量的赋值。
Python中的赋值类似于c++中的引用,本质是对变量对象的引用,获得对方所指向的内存地址
-
对于不可变类型
我们对变量的赋值操作,本质上只是把等号右边的值所在的内存地址给了左边的变量
从上图我们可以看出,a、b均通过赋值得到了“hello world”的内存地址之后,即使对a重新赋值,也只是a得到了新建的值的地址,对已赋值的b没有影响
-
对于可变类型
从上图我们可以看到a、b均通过赋值得到了一个列表,虽然表面上我们分别对a、b列表的内容进行了修改,但实际上修改的却是内存中该列表所指向的内部元素,因此,他们的修改会互相影响(他们本就共用的同一个列表)
浅拷贝
浅拷贝可用copy模块中的copy函数,进行浅拷贝时,只会拷贝该变量元素的地址(可以理解为只拷贝了第一层)。
我们可以看到,浅拷贝只是新建了一块内存,用于将列表a中的各元素地址拷贝了出来,b得到的是一个新的内存地址,只不过b所指向的内存中各元素地址和a中的相同。
因此,如果元素是不可变类型,则修改只会改变各自的地址,互相之间没有影响,但如果某个元素是可变类型,则对其内容的修改并不会改变这个元素本身的地址,就会互相影响到。
深拷贝
浅拷贝可用copy模块中的deepcopy函数,深拷贝会完全复制原变量相关的所有数据,在内存中生成一套完全一样的内容,在这个过程中我们对这两个变量中的一个进行任意修改都不会影响其他变量。