Python从动态类型到对象拷贝

动态类型

在我们的Java、C这些语言中,我们在定义变量的时候,都会指定它的数据类型,但是在python中却没有这样的操作,因为python中的类型是在运行的过程中决定的,而不是同于预先的定义来声明的。

python中的变量名和对象是分开的,变量名永远没有任何关联的类型信息,类型只和对象关联。一个变量名当第一次被赋值时被创建,而当新的赋值表达式出现时,它会马上被当前引用的对象所替代。这就是python所谓的动态类型机制。这个变量名我们其实就是指向具体对象的一个引用。

a = 'abcde'
print(a)
a = [1,2,3,4,5]
print(a)

abcde
[1, 2, 3, 4, 5]

结合上面这个简单的例子,我们再来从头仔细理一理:

1、创建了一个字符串对象’abcde’,然后创建了一个变量a,将变量a和字符串对象 ‘abcde’相连接,

2、之后又创建了一个列表对象[1,2,3,4,5],然后又将他和a相连接。

这种从变量到对象的连接,我们称之为引用,以内存中的指针形式实现。因此直白的说,在内部,变量事实上是到对象内存空间的一个指针,而且指向的对象可以随着程序赋值语句而不断变化。

总结一下:变量名没有类型,只有对象才有类型,变量只是引用了不同类型的对象而已。每一个对象都包含了两个头部信息,一个是类型标志符,标识这个对象的类型,以及一个引用的计数器,用来表示这个对象被多少个变量名所引用,如果此时没有变量引用他,那么就可以回收这个对象。

共享引用

x = [1,2,3,4]
L = ['a',x,'b']
D = {'z' : 3,'y' : x}
print(L)
print(D)

x[3] = 10
print(L)
print(D)

x1 = x
x1[2] = 20
x[0] = 30
print(x)
print(x1)


['a', [1, 2, 3, 4], 'b']
{'z': 3, 'y': [1, 2, 3, 4]}
['a', [1, 2, 3, 10], 'b']
{'z': 3, 'y': [1, 2, 3, 10]}
[30, 2, 20, 10]
[30, 2, 20, 10]

对于上面这段代码与输出结果,当我们更改x或x1的任何一个值时,x1与x的输出都是一样的,那么说明这两个变量都是指向同一个对象,我们把这个叫做共享引用。前面我们说过变量就是对象的引用。

对于赋值操作来说,总是存储对象的引用,而不是这些对象的拷贝。所以我们在修改可变对象的时候也会影响到其他引用该对象的变量。说直白点就是对象一直只有那一个,引用有很多个,所以你更改对象的内容,大家都会收到影响。

那么我想获得对象独立的复制,该怎么做呢?

我们有以下方法,1、copy方法也能够实现完全复制;2、内置函数list可以生成拷贝。3、分片表达式能返回一个新的对象拷贝,没有限制条件的分片表达式能够完全复制列表。

X = [1,2,3,4,5,6]

c1 = X.copy()
c1[0] = 10
print(X)
print(c1)

c2 = list(X)
c2[0] = 20
print(X)
print(c2)

c3 = X[1:4]
c3[0] = 30
print(X)
print(c3)

c4 = X
c4[0] =40
print(X)
print(c4)

输出:
[1, 2, 3, 4, 5, 6]
[10, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
[20, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
[30, 3, 4]
[40, 2, 3, 4, 5, 6]
[40, 2, 3, 4, 5, 6]

赋值、浅拷贝和深拷贝

1、对于直接赋值,两个引用指向同一个对象,所以对象改变,赋值也会跟着变化。

2、浅拷贝,是不会拷贝子对象的(即共享子对象),原始数据改变,子对象也会跟着变化。但是直接引用所指对象不会变化,因为完成了赋值。例子中用到了切片和copy两种方式实现。

3、深拷贝,包含对象里面的子对象的拷贝,所以原始对象变化不会改成拷贝对象的变化。

import copy
X = [1,2,3,]
L = [1,2,3,4,X]
A = L
print(A)
A[1] = 100
A[4].append(4000)
print(A)
print(L)
print(X)
print()

L = [1,2,3,4,X]
B = L[:]
print(B)
B[1] = 200
B[4].append(1000)
print(B)
print(L)
print(X)
print()

L = [1,2,3,4,X]
C = copy.copy(L)
print(C)
C[1] = 300
C[4].append(2000)
print(C)
print(L)
print(X)
print()

L = [1,2,3,4,X]
D = copy.deepcopy(L)
print(D)
D[1] = 400
D[4].append(3000)
print(D)
print(L)
print(X)
print()

输出:

[1, 2, 3, 4, [1, 2, 3]]

[1, 100, 3, 4, [1, 2, 3, 4000]]

[1, 100, 3, 4, [1, 2, 3, 4000]]

[1, 2, 3, 4000]

 

[1, 2, 3, 4, [1, 2, 3, 4000]]

[1, 200, 3, 4, [1, 2, 3, 4000, 1000]]

[1, 2, 3, 4, [1, 2, 3, 4000, 1000]]

[1, 2, 3, 4000, 1000]

 

[1, 2, 3, 4, [1, 2, 3, 4000, 1000]]

[1, 300, 3, 4, [1, 2, 3, 4000, 1000, 2000]]

[1, 2, 3, 4, [1, 2, 3, 4000, 1000, 2000]]

[1, 2, 3, 4000, 1000, 2000]

 

[1, 2, 3, 4, [1, 2, 3, 4000, 1000, 2000]]

[1, 400, 3, 4, [1, 2, 3, 4000, 1000, 2000, 3000]]

[1, 2, 3, 4, [1, 2, 3, 4000, 1000, 2000]]

[1, 2, 3, 4000, 1000, 2000]

Python中的比较、相等性与真值的问题

L1 = [1,2,['A','B']]
L2 = [1,2,['A','B']]
L3 = L1
print(L1 == L2, L1 is L2)
print(L1 == L3, L1 is L3)
输出:
True False
True True

==是比较两个对象值的相等与否,即递归的比较所有的内嵌对象。

is是测试两个对象的一致性,比较的是两者的内存地址是否一样。

还有一点,python中将False、None、各种类型的数值0、空序列、空映射都被视为假,其他各种值都是真。

https://zhuanlan.zhihu.com/p/32475317

https://www.cnblogs.com/xueli/p/4952063.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值