python中对象、传递与拷贝

python对象

  Python 中,一切皆对象。每个对象由:标识(identity)、类型(type)、value(值)组成。

标识用于唯一标识对象,通常应用于对象在计算机内存地址。使用内置函数id(obj)可返回对象obj的标识。

同时要注意类型是属于对象的,而不是变量。而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象。

python的传递

  python中的传递是引用传递。变量就是对象的引用,变量中存着对象的内存地址。

  python是动态语言。变量不需要显示声明类型(type),根据变量引用的对象,python解释器自动确定数据类型。

  python是强类型语言,每个对象都有数据类型,并只支持该类型支持的操作。

  变量存放在栈中,中存放的obj的内存地址。而obj存放在中。堆中的这个obj存着:value、type、id(内存地址)。

  

 

 

   不可变对象

  在不可变对象中,变量和对象是互相独立的,当新建一个变量指向对象是不会对对象有任何影响。

a = "123"
b = a
a = "xyz"

print (a)
print (b)

这个打印结果就是"xyz" "123"。对照上面的内存图。这就解释了为什么说python的变量是个标签。当b=a , a=xyz时,a这个变量就跟标签一样就贴在了"xyz"这个对象上(实质上是新的内存地址赋给了a)。由原来"123"有两个标签a和b,变成了b指向123,a指向新的对象xyz。这些前提一定要基于对象是不可变对象(strings, tuples, 和numbers)。

   可变对象

  在可变对象(list,dict,set)中,如果会直接在当前对象进行操作。并不会为新的变量进行副本拷贝。

a = [1, 2, 3]
b = a
a[0], a[1], a[2] = 4, 5, 6 //改变原来 list 中的元素
>>> a
[4, 5, 6]
>>> b
[4, 5, 6]

浅拷贝和深拷贝

  浅拷贝

    对于不可变类型,浅复制仅仅对内存地址进行复制,不会开辟新的内存空间。

    对于可变类型,浅复制会开辟新的内存空间(仅仅是最顶层开辟了新的空间,里层的元素地址还是一样的)。子序列中的元素地址还是一样的(新旧对象子序列是共享的)。

    浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象的;改变原始对象中为不可变类型的元素的值,只有原始类型受影响。

    

  

  深拷贝

    浅拷贝,除了顶层拷贝,还对子元素也进行了拷贝(本质上递归浅拷贝)。

    经过深拷贝后,原始对象和拷贝对象所有的元素地址都没有相同的了(对于不可变对象指向相同的地址空间,可变对象序列内存地址就不同了)。

 

import copy
a = [1, 2, 3, 4, ['a', 'b']]#原始对象

b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝

a.append(5) #修改对象a

a[4].append('c') #修改对象a中的['a', 'b']list对象

print ('a = ', a)
print ('b = ', b)
print ('c = ', c)
print ('d = ', d)
print(id(a))
print(id(c))
print(id(d))

结果:

 

 

 

 

 当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛钱关系。

函数内的引用指向的是可变对象,对它的操作就和定位了指针一样,在内存里进行修改。

如果两个对象是同一个类的实例对象,使用 is 和 == ,结果都是false。但是实例对象里的值是相等的,这时候可以重载运算符来解决这个问题。

 

posted @ 2019-12-01 11:31  L1m1t  阅读(1764)  评论(0编辑  收藏  举报