python变量类似于引用式变量,因此可以理解为附加在对象上的标注

charles = {"name": 'charles', "age": 30}
lews = charles
print(charles==lews)
print(charles is lews)

元组的相对不可变性:

集合,列表,字典等python集合保存的式=是对象的引用,元组的不可变性指的是tuple数据结构的物理内容(及保存的引用)不可变,与引用的对象无关。

t1 = (1, 2, [3, 4])
t2 = (1, 2, [3, 4])
print(t1 == t2)   # true
print(t1 is t2)   # false
print(id(t1[-1]))
t1[-1].append(5)
print(t1)
print(id(t1[-1]))  # 依然不可变 这才是元组不可变的本质

副本与源对象, 浅复制

复制列表等可变对象,有两种方法:

# method 1
a = [12, 23, [11, 22], (7, 8, 9)]
b = list(a)    # a是源对象, b是副本# method 2
b = a[:]    # 复制

copy模块提供的copy()和deepcopy()能为任意对象做求浅复制和深复制

from copy import copy, deepcopyclass Bus:def __init__(self, passengers=None):if passengers is None:self.passengers = []else:self.passengers = list(passengers)def drop(self, name):self.passengers.remove(name)def pick(self, name):self.passengers.append(name)def __repr__(self):return "Passengers are: " + str(self.passengers)if __name__=="__main__":passenger = ["Lily", "Nosy", "Tom"]bus1 = Bus(passenger)bus2 = copy(bus1)      # copy函数bus3 = deepcopy(bus1)   # deepcopy函数print(bus1)bus1.pick("liu")print(bus1)print(bus2)print(bus3)

输出结果:

此外,可以通过实现特殊方法__copy__()和__deepcopy__()能够控制copy的行为。

参数传递

python唯一支持的参数传递模式是共享传参。共享传参指函数的各个形式参数获得实参中各个引用的副本,也就是说函数内部的实参是形参的别名。

可对上面的程序做一个小的修改

from copy import copy, deepcopyclass Bus:def __init__(self, passengers=None):if passengers is None:self.passengers = []else:# self.passengers = list(passengers)   # 相当于创建实参的一个副本,所以形参变化,实参不变化self.passengers = passengers   # 形参是实参的别名,python中参数传递的方式def drop(self, name):self.passengers.remove(name)def pick(self, name):self.passengers.append(name)def __repr__(self):return "Passengers are: " + str(self.passengers)if __name__=="__main__":passenger = ["Lily", "Nosy", "Tom"]bus1 = Bus(passenger)bus2 = copy(bus1)      # copy函数bus3 = deepcopy(bus1)   # deepcopy函数print(bus1)bus1.pick("liu")print(bus1)print(bus2)print(bus3)print(passenger)   # pick方法对函数内部的形参做了修改# 形参是实参的引用,所以说实参也会跟着变化

不同类型的对象的实参,传入函数中后,会受到不同的影响

1. 数组和元组没变

2. 列表变了

不适用可变类型作为函数的默认值

可选参数可以有默认值,这是python的一个特性,能保证API在进化的时候向后兼容, 但是,应该避免使用可变的对象作为参数的默认值。

例如对上面的代码作如下修改:

    passenger = ["Lily", "Nosy", "Tom"]bus1 = Bus(passenger)bus1.pick("wang")bus1.drop("Lily")print(bus1)bus2 = Bus()   # 使用了默认的参数值print(bus2)bus2.pick("zhang")bus3 = Bus()   # 使用默认参数,但此时默认的参数(可变对象)已经被修改print(bus3)    # 修改了之后。bus3中有值了

输出结果:

在修改bus2的时候,实际上修改了传递给构造方法的那个列表,所以bus3中出现了一个“幽灵” 乘客。

正确的做法是:Bus类应该自己维护passenger列表,应该做到在构造方法中将实参的副本传递给实参。这样就不会影响初始化的时候传递的参数了。

del和垃圾回收:

del语句删除名称,而不是对象,del命令可能会导致对象被当作垃圾回收,但是仅当删除的变量保存的是对象的最后一个引用的时候。

cpython中,垃圾回收采用的算法是引用计数,实际上,每个对象都会统计有多少个引用指向自己,当引用计数归零时,对象立即会被销毁。

python 对象引用,可变性,垃圾回收相关推荐

  1. 流畅的python第八章--对象引用 可变性 垃圾回收

    本章内容: 对象引用 : 引用式变量 对象标识符,值,别名 可变性 元组特性 潜复制和深复制 引用和函数参数 垃圾回收 删除对象 弱引用 提示:本章内容理解不清很可能出现不易发现的错误 8.1 变量不 ...

  2. python进阶19垃圾回收GC

    原创博客链接:python进阶19垃圾回收GC 垃圾收集三大手段 一.引用计数(计数器) Python垃圾回收主要以引用计数为主,分代回收为辅.引用计数法的原理是每个对象维护一个ob_ref,用来记录 ...

  3. python和ruby垃圾回收机制

    先了解一下蟒蛇中的其他概念: 1.小整数对象池 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间. Python对小整数的定义是[-5,257 ...

  4. 流畅的python 对象引用 可变性和垃圾回收

    对象引用.可变性和垃圾回收 变量不是盒子 人们经常使用"变量是盒子"这样的比喻,但是这有碍于理解面向对象语言中的引用式变量.Python 变量类似于 Java 中的引用式变量,因此 ...

  5. python入门系列:对象引用、垃圾回收、可变性

    Python中的变量是什么 引言 Python和java中的变量本质不一样,java的变量可以理解为一个盒子,用来容纳我们的对象,使用前要先声明它,好分配给我们合适的内存空间.Python的变量可以理 ...

  6. python中的垃圾回收机制_python里面的垃圾回收机制

    1.引用计数机制: python里每一个东西都是对象,它们的核心就是一个结构体:PyObject typedef struct_object { int ob_refcnt; #引用计数 struct ...

  7. python如何进行垃圾回收_python垃圾回收机制

    一.引入 ​ 解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题,当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉 ...

  8. python垃圾回收 循环引用_在做 Python 循环引用垃圾回收实验中的一个小问题, Python3 的 print 是线程安全的吗?...

    以前都听说 Python 循环引用会导致引用数无法清零,所以不能垃圾回收,会内存泄漏,需要删除引用关系或者用 gc.collect()才能进行正常垃圾回收. 但做了下实验,好像还是会自动回收循环引用的 ...

  9. Python学习:垃圾回收机制

    Python 程序在运行的时候,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量:计算完成后,再将结果输出到永久性存储器中.如果数据量过大,内存空间管理不善就很容易出现 OOM(out of ...

  10. 【Python核心】垃圾回收机制

    Python程序在运行的时候,需要在内存中开辟出一块空间用于存放运行时产生的临时变量,计算完成后再将结果输出到永久性存储器中 如果数据量过大,内存空间管理不善就很容易出现OOM(out of memo ...

最新文章

  1. day 58 关于bootstrap
  2. 安全访问服务边缘(SASE)是什么?
  3. 10 行 Java 代码实现 LRU 缓存
  4. java数组子类型_[改善Java代码]数组的真实类型必须是泛型类型的子类型
  5. Cocos游戏引擎3D特效全新升级 更流畅更炫酷
  6. Heartbeat VIP/IP 与 别名/辅助IP
  7. cla c 语言编译器,第九章 CLA_C2000_C_Compiler.pdf
  8. 宏定义函数container_of的解释
  9. SP2010开发和VS2010专家食谱--第六章节--Web Services和REST(5)--Inserting new contacts through REST...
  10. 异常的总结 java 1615387415
  11. jquery.validate+jquery.form提交的三种方式
  12. Install Java on Ubuntu server
  13. c语言中优先级队列_C ++中的优先级队列
  14. FAQ系列 | 用MySQL实现发号器
  15. C#基础知识梳理系列七:字符串
  16. 最新PHP扩展SG11解密教程分享+视频模式
  17. 大数据分析及工具应用总结
  18. html鼠标各种坐标,HTML坐标系与鼠标事件坐标
  19. 旋转拖动验证码解决方案
  20. 8*8点阵动态显示 I 爱 U

热门文章

  1. 认证授权介绍_Spring Security OAuth2.0认证授权---springcloud工作笔记109
  2. 大数据_Hbase-(数据写入流程)---Hbase工作笔记0009
  3. Lua开发工作笔记0001---什么是热更新为什么要热更
  4. SpringCloud工作笔记071---mysql字符集 utf8 和utf8mb4 的区别_utf8是不能存储emoji表情字符集的
  5. latax 使用说明
  6. powerdesigner连接mysql,并导出其数据模型的方法
  7. C++中this指针的用法
  8. java clone原理_cloneAble接口实现clone()原理
  9. mysql冷区域热区域_mysql的数据备份方式,及热备与冷备的优缺点对比
  10. c语言作业的分析,C语言作业分析.doc