Python对象及内存管理机制

Python是一门面向对象的编程语言,python中一切皆为对象,对每一个对象分配内存空间,python的内存管理机制主要包括引用计数、垃圾回收和内存池机制 。本文简要介绍python对象及内存管理机制 。
参数传递常见的参数传递有值传递和引用传递

  • 值传递就是拷贝参数的值,然后传递给新变量,这样原变量和新变量之间互相独立,互不影响 。
  • 引用传递指把参数的引用传给新的变量,这样原变量和新变量指向同一块内存地址 。其中任何一个变量值改变,另外一个变量也会随之改变 。
Python 参数传递Python 的参数传递是赋值传递(pass by assignment),或者叫作对象的引用传递(pass by object reference) 。在进行参数传递时,新变量与原变量指向相同的对象 。下面先来看一下Python中可变和不可变数据类型赋值的例子 。
1. 不可变数据类型整型(int)赋值:
a = 1print(id(a))b = aprint(id(b))a = a + 1print(id(a))c = 1print(id(c))执行结果:
140722100085136140722100085136140722100085168140722100085136其中id()函数用于返回对象的内存地址 。
可以看到b,c都指向了相同的对象,而a = a + 1 并不是让 a 的值增加 1,而是重新创建并指向了新的值为 2 的对象 。最终结果就是a指向了2这个新的对象,b指向1,值不变 。
2. 可变数据类型以列表(list)为例:
l1 = [1, 2, 3]print(id(l1)) # l2 = l1print(id(l2))l1.Append(4)print(id(l1))print(l1)print(l2)执行结果:
【Python对象及内存管理机制】193320277229619332027722961933202772296[1, 2, 3, 4][1, 2, 3, 4]l1 和 l2 指向相同的对象,由于列表是可变(mutable)数据类型,所以 l1.append(4)不会创建新的列表,仍然指向相同的对象 。由于l1 和 l2 指向相同的对象,所以列表变化也会导致l2的值变化 。
可变对象(列表,字典,集合等)的改变,会影响所有指向该对象的变量 。对于不可变对象(字符串、整型、元组等),所有指向该对象的变量的值总是一样的,也不会改变 。
Python中的'==' 和 'is'== 和 is是Python 对象比较中常用的两种方式,== 比较对象的值是否相等, is 比较对象的身份标识(ID)是否相等,是否是同一个对象,是否指向同一个内存地址 。
a = 1b = aprint(id(a))print(id(b))print(a == b)print(a is b)执行结果:
140722100085136140722100085136TrueTruea和b的值相等,并指向同一个对象 。在实际应用中,通常使用== 来比较两个变量的值是否相等 。is 操作符常用来检查一个变量是否为 None:
if a is None:print("a is None")if a is not None:print("a is not None")Python浅拷贝和深度拷贝前面介绍了Python的赋值(对象的引用传递),那么Python如何解决原始数据在函数传递后不受影响呢,Python提供了浅度拷贝(shallow copy)和深度拷贝(deep copy)两种方式 。
  • 浅拷贝(copy):拷贝父对象,不拷贝对象内部的子对象 。
  • 深拷贝(deepcopy):完全拷贝了父对象及其子对象 。
浅拷贝1. 不可变数据类型下面对不可变对象整型变量和元组进行浅拷贝:
import copya = 1b = copy.copy(a)print(id(a))print(id(b))print(a == b)print(a is b)t1 = (1, 2, 3)t2 = tuple(t1)print(id(t1))print(id(t2))print(t1 == t2)print(t1 is t2)执行结果:
5062207250622072TrueTrue5514538455145384TrueTrue不可变对象的拷贝和对象的引用传递一样,a、b指向相同的对象,修改其中一个变量的值不会影响另外的变量,会开辟新的空间 。
2. 可变数据类型对可变对象list进行浅拷贝:
import copyl1 = [1, 2, 3]l2 = list(l1)l3 = copy.copy(l1)l4 = l1[:]print(id(l1))print(id(l2))print(l1 == l2)print(l1 is l2)print(id(l3))print(id(l4))l1.append(4)print(id(l1))print(l1 == l2)print(l1 is l2)执行结果:
4852090448523784TrueFalse485238484852103248520904FalseFalse可以看到,对可变对象的浅拷贝会重新分配一块内存,创建一个新的对象,里面的元素是原对象中子对象的引用 。改变l1的值不会影响l2,l3,l4的值,它们指向不同的对象 。
上面的例子比较简单,下面举一个相对复杂的数据结构:
import copyl1 = [[1, 2], (4, 5)]l2 = copy.copy(l1)print(id(l1))print(id(l2))print(id(l1[0]))print(id(l2[0]))l1.append(6)print(l1)print(l2)l1[0].append(3)print(l1)print(l2)执行结果:
1918057951816191805794944826803289914962680328991496[[1, 2], (4, 5), 6][[1, 2], (4, 5)][[1, 2, 3], (4, 5), 6][[1, 2, 3], (4, 5)]


推荐阅读