马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 sunrise085 于 2020-3-16 13:02 编辑
在python编程中,我们经常会用到各种变量,每个变量都会有变量名,在程序中我们还可能会对变量进行各种修改操作。我们修改变量的时候到底修改的是什么呢?(昨天我再写这个帖子的时候,看到有个鱼油提出了很相近的问题,我感觉需要加快发布这个帖子,和大家进行一下交流) 话不多说,直接结合例程进行分析~~ num1=123
num2=num1
num1+=333
print('num1=',num1)
print('num2=',num2)
print()
list1=['A','B','C']
list2=list1
list1.append('D')
print('list1=',list1)
print('list2=',list2)
程序运行结果:
num1= 456
num2= 123
list1= ['A', 'B', 'C', 'D']
list2= ['A', 'B', 'C', 'D']
这个例程中,共有两部分内容。第一部分是对整型变量int的赋值与修改操作,第二部分程序时对列表list的赋值与修改操作。但是运行结果却不一样。这是为啥呢?
这就需要理解python中变量空间的分配、变量名的指向等知识。
第一部分,下图左侧是执行完前两行代码的结果(地址是随便编的),右侧则是执行完第三行代码的结果。
第二部分,下图左侧是执行完第7、8行的结果,右侧是执行完第9行的结果。
在python中,整型int、字符串string、列表list、集合set、字典dict等等都可称之为对象,而这些不同类型的对象是有区别的,可以分为两类:不可变类型对象和可变类型对象。数字numbers、字符串string、元组tuples等是不可变类型对象,列表list、字典dict、集合set等是可变类型对象。 不可变类型对象就是一旦生成,就不可更改的对象,而可变类型对象是生成之后可以进行增删改等修改操作的对象。
对于不可变类型对象的修改操作实际上是创建了一个新的对象,然后将变量名(即标签)贴在新的对象上,这样我们就以为是修改了该变量了。对于可变类型对象的修改操作就是对原对象的修改。
变量名实际上应该称之为标签,我们会把各个标签贴在各个对象上,同一个对象可以有多个标签,但是一个标签不能贴在多个对象上。
在这个例程中,先看第一部分程序。首先生成一个int类型对象123,并将标签num1贴在该对象上,这个对象是不可变类型的对象;然后在该对象上又贴了一个标签num2;第三句程序是num1=num1+222,这里并不是对int类型的对象123进行修改,因为该类型的对象是不可修改的,实际上是生成一个新的对象,对象的值是123+222=456,然后将num1标签贴在该对象上。此时有两个int型的对象,分别贴有标签num1和num2,输出两个标签所指向的对象值,即为程序运行的结果。 再看第二部分程序,首先生成一个list类型的对象['A','B','C'],并将标签list1贴在该对象上,这个对象是可变类型的对象;然后在该对象上又贴了一个标签list2;第三句程序list1.append('D'),这里是直接对之前生成的list类型对象['A','B','C']进行的元素追加修改,是在原对象的位置进行的修改,并没有创建新对象。因此此时仍然只有一个对象,标签list1和list2都贴在了这个对象上,输出两个标签所指向的对象值自然就是同一个结果了。 那么若是想创建两个完全一样的可变类型对象应该如何创建呢,直接再敲一遍代码吗?
肯定不需要啊!
看以下程序: import copy
mylist1=[[1,2,3],2,3]
mylist2=mylist1 #标签赋值
mylist3=mylist1[:] #切片赋值,或者称之为浅拷贝,相当于mylist3=copy.copy(mylist1)
mylist4=copy.deepcopy(mylist1) #深度拷贝赋值
mylist1[1]=9
mylist1[0][1]=8
print('mylist1=',mylist1)
print('mylist2=',mylist2)
print('mylist3=',mylist3)
print('mylist4=',mylist4)
程序运行结果: mylist1= [[1, 8, 3], 9, 3]
mylist2= [[1, 8, 3], 9, 3]
mylist3= [[1, 8, 3], 2, 3]
mylist4= [[1, 2, 3], 2, 3]
这段程序中用了三种不同的方法将标签mylist1的对象分别赋值给三个新的标签,然后对mylist1的变量进行了修改。最后输出这四个标签所指向的对象。然后发现mylist1和mylist2完全一样,这个在上文中已经讲了。
接下来我们看看mylist3,这个是切片赋值,切片赋值是创建了一个新对象,因此将原对象mylist1的元素1改为9,不影响mylist3的值。接着我们有对mylist1的子对象进行了修改,发现mylist3的子对象也跟着修改了。为啥呢?不是创建新对象了么?咋还跟着原对象变了呢?这里就设计到另外一个知识点,就是python的浅拷贝和深拷贝。切片赋值是浅拷贝,相当于mylist3=copy.copy(mylist1),只拷贝的父对象,而不会拷贝里面的子对象,子对象仍然是原来对象的子对象,因此就出现了以上现象。要想完全拷贝赋值,则需要使用深拷贝,即copy.deepcopy(),deepcopy()方法可以进行完全拷贝,既对父对象进行了拷贝,也对子对象进行了拷贝。是一个全新的对象了。因此mylist4完全不受mylist1的影响了。
注意:深拷贝需要引入copy模块!!
以上就是个人对变量的修改与赋值的相关解析,看了一些相关资料之后进行的整理。可能会有不足之处,希望大家多多交流,相互交流,一起讨论,共同进步!!
|