Python中万物皆对象,变量是对象,方法是对象………
Python对象的引用分为浅拷贝和深拷贝以及类的方法引用
一.引用的理解:其实就是对象的指针
- 引用是内存中真实对象的指针,表示为变量名或内存地址
- 每个对象至少存在1个引用,id()函数用于获取引用
- 在传递参数和赋值时,python传递对象的引用,而不是复制对象
举例:对象的指针是引用
ls = [1,2,3,4,5]
lt = ls
print(id(ls))
print(id(lt))
列表类被实例化,给出了ls,而ls赋值给lt并没有真正实例化,而仅仅是将指针复制了一份.
二.Python内部机制对引用的处理:
- 不可变对象:immutable解释器为相同值维护尽量少的内存区域
- 可变对象:mutable解释器为每个对象维护不同内存区域
(1).对不可变对象的引用:
举例:
a = 10
b = a
c = 10
print(id(a))
print(id(b))
print(id(c))
结果:
Python为相同的值开辟了同一块内存区域,除了整数类似的还有字符串等,当然浮点数也可以.但是有一种情况除外.
a = "as"
b = a
c = "as"
d = "a"
e = "s"
f = d+e
print(id(a))
print(id(b))
print(id(c))
print(id(d))
print(id(e))
print(id(f))
结果:
虽然f与a相等,但是python不会对未来的结果进行计算,他会对结果新开辟一块空间.所以相同的结果可能有不同的内存地址.
(2).对可变对象的引用
可变对象类型,只要被创建就会独立的分配内存空间
举例:
a = []
b = a
c = []
print(id(a))
print(id(b))
print(id(c))
结果:
对于引用,只要有一个引用向内存空间做了修改,另外一个引用就会发生变化.
例子:
a = []
b = a
b.append(1)
print(a,id(a))
print(b,id(b))
结果:
三.引用的理解
1.导致引用+1的情况:
对象被创建:d = class()
对象被引用:a = d
对象被作为函数或方法的参数:sys.get(d)
对象被作为一个容器中的元素:ls = [d]
2.导致引用-1的情况:
对象被删除:del d
对象的名字被赋予新的对象:d = 123
对象离开作用域:foo()函数的局部变量count
对象所在容器被删除: del ls
四.对象的拷贝
拷贝分为浅拷贝和深拷贝
拷贝:复制一个对象为新的对象,内存空间有”变化”
浅拷贝:仅复制最顶层对象的拷贝方式,默认拷贝方式
深拷贝:迭代复制所有对象的拷贝方式
浅拷贝
例子:
a =
["sss",[886]]
b = a.copy()
c = a[:]
d = list(a)
print("a",id(a),a)
print("b",id(b),b)
print("c",id(c),c)
print("d",id(d),d)
结果:
也就是说,经过拷贝,切片,类型定义,内存位置都发生了变化.注意,这里如果是整数类型,或者说是不可变类型,类型重定义为同种类型,内存地址不发生变化.
copy一般是对可变数据类型,list和array中有copy
上述程序中,列表中的元素的地址都相同,也就是说列表被拷贝了,但元素没有被拷贝.因为上述对象被作为一个容器中的元素:ls = [d]引用+1,故ls包含的实际上是一个指向字符串"sss"的指针和一个指向列表[886]的指针.实际上复制的是指针,或者说引用,并没有复制每个元素的内存空间.这就是浅拷贝.带来的问题是这些浅拷贝中对一个其中可变元素进行改变,其他的浅拷贝中都发生了变化.
a = [1,2,[3]]
b = a.copy()
b[-1].append(2)
print(id(a),a)
print(id(b),b)
a = [1,2,[3]]
b = a.copy()
b.append(2)
print(id(a),a)
print(id(b),b)
左边全都发生变化,因为拷贝的里面的指针中的值生了变化,右边只有b发生了变化,因为此时改变的只是列表中的引用.细细体会!
深拷贝
(1).Python不默认支持深拷贝.
采用copy库的deepcopy()方法
迭代拷贝对象内各个层次对象,完全新开辟内存建立对象
深拷贝仅针对可变类型,不可变类型无需创建新对象,也就是说拷贝对象元素中包含不可变类型,那么深拷贝后,该不可变类型内存地址依旧不变.
(2).与浅拷贝的区别:
浅拷贝:仅复制最顶层对象的拷贝方式,默认拷贝方式
深拷贝:迭代复制所有对象的拷贝方式,采用copy库的deepcopy()
一般深拷贝都与可变类型关联
五.类的方法引用
定义方式:def <实例方法名>(self,<参数列表>)
实例方法名也是一种引用,即对方法本身的引用
当方法被引用时,方法(即函数)将产生一个对象:方法对象
两个例子类方法的引用:
<对象名>.<方法> 是对一个方法的引用,注:方法后面没有方法参数
class Deo:
def __init__(self,name):
self.name = name
def
lucky(self,salt= 0):
s = salt**2
return s
dc1 =
Deo("laowang")
lucky = dc1.lucky
#对象名.方法名就是这个方法的引用
print(Deo.lucky(dc1,10))
print(dc1.lucky(10))
print(lucky(10))
a =
[1,2,3]
b = a.copy()
b.append(2)
c = a.append#方法引用
c(4)
print(id(a),a)
print(id(b),b)
结果:
注:<对象名>.<方法名>(方法参数)
等价于
<类名>.<方法名>(<对象名>,方法参数)