对象引用、可变性、垃圾回收

变量视作便利贴

变量 a,b 引用同一个列表

赋值:把变量分配给对象。先有对象
Python 变量类似 Java 中的引用式变量

标识

对象一旦创建,它的标识绝不会更改
可以把标识理解为内存地址,is 运算符比较两对象的标识;id() 返回对象的标识的整数表示

is 与 ==

  • == 比较的是值,is 比较的是两个整数 id
  • is 比 == 快,因为 is 不能重载,而 == 背后是 a._eq_(b),object 的 _eq_ 比较的是两对象的 id,与 is 一致。
    但多数内置类型覆盖了此方法,考虑对象的属性的值,为此做相等性测试可能涉及大量处理工作。
  • 变量与单例值比较应使用 is。 x is None;x is not None

tuple 的相对不可变性

  • 容器序列保存的是对象的引用
    单一数据类型的扁平序列在连续内存中保存的是数据本身
  • tuple 不可变指 tuple 的物理内容(保存的引用)不可变。与引用的对象无关!


    区分赋值与 append

默认做浅复制

  • 浅复制:只复制最外层容器,副本中的元素是源容器元素的引用
    使用构造方法或 [ : ] 实现


    浅复制
  • 对于可变对象元素,由于存放的是引用,复制的也是引用。一个列表改变,另外一个列表也改变。
  • 对于不可变对象元素,虽然存放的是引用,复制的也是引用。
    但只要发生改变,实质是创建了新对象,原来的对象还是不会变。自然不会影响到另外一个列表

深复制

深复制:副本【与源本不共享内部对象】copy.deepcopy(object)
浅复制:copy.copy(object),背后分别是 _copy_()、_deepcopy_()

参数传递

Python 使用的是共享传参(call by sharing),即形参是实参的别名


call by sharing
  • x 是不可变对象,当 x += y 时,实质创建了新对象,且新对象的作用域只在函数内,原来的 x 没变。
  • p 是可变对象,当 p += q 时,p 已经变了。

不要使用可变对象作为函数默认值

  • 默认值在定义函数时计算(通常在加载模块时,也就是导入模块时),即 passen=[] 只在加载模块时执行一次,
    因此默认值变成了函数这个对象的属性。
    如果默认值是可变对象,而且修改了它的值,后续函数调用都会受到影响。


    默认值
  • 所以通常使用 None 作为接受可变值参数的默认值

防御可变参数

def __init__(self, passengers=None):
    if passengers is None:
        passen = []
    else:
        self.passengers = list(passengers)
  • 用 None 作为接受可变值参数的默认值
  • 如果直接 self.passengers = passengers 还是不够妥当,因为这样形参和实参共享同一个对象,形参变了,实参也会发生改变。list(passengers) 相当浅复制了 passengers。反正一句话,不要直接对形参进行操作,否则会影响实参。应该生成形参副本再操作。

del 和垃圾回收

引用计数
CPython 垃圾回收算法。当对象的引用归零时,CPython 会在对象上调用_del_ 方法(前提是定义了),然后释放分配给对象的内存。
分代垃圾回收
CPython 2.0 增加的算法。
如果一组对象全是相互引用,如: a = [2, 3], b= [a, 5], a.append(b)
即使再出色的引用方式也会导致组中对象不可获取。

del 不会删除对象,但 del 导致对象不可获取从而被删除

  • weakref.finalize(s1, bye):在 s1 引用的对象上注册 bye 回调函数

弱引用

  • 上例中,finalize 持有 {1, 2, 3} 的弱引用
  • 在「缓存」中,经常要引用对象,却不让对象存在时间超过所需时间
  • 弱引用不会增加对象引用数量,弱引用引用的对象称为「所指对象 referent」。弱引用不会影响 referent 被当作垃圾回收


    弱引用
  • wref() 会返回被引用对象,因为这是控制台会话,返回的对象会绑定到 _ 变量
  • 即使删除了引用 a,仍有引用 _ 绑定对象 {0, 1}
  • 当使用 wref() is None 时,_ 会绑定返回值 False,这时对象{0, 1} 就没有引用了


    _ 自动绑定 wref() 返回对象

WeakValueDictionary

  • weakref.ref 类是底层接口(少用),较常用的是 finalize 和 weakref 集合(WeakKeyDictionary、WeakValueDictionary、WeakSet)
  • WeakValueDictionary 类实现的是可变映射,
    里面的值是对象的弱引用,被引用的对象被回收后,
    对应的键自动从 WeakValueDictionary 中删除。
    常用作「缓存」
    WeakValueDictionary
  • stock 是WeakValueDictionary 的一个实例,值是对象的弱引用。
  • del catalog 意味着被引用的对象被回收,按道理来说,stock 的键也会自动删除,但是最后一个键被保留了。
  • 这时因为 for 循化中的 cheese 是全局变量,循环结束后绑定着对象 Cheese('ccc'),所以del catalog 后,对象 Cheese('ccc') 仍有引用 cheese,所以不被当作垃圾回收,直至 del cheese 后才被当作垃圾回收,对应的键也就自动删除。

weakSet
保存元素弱引用的集合类,当元素没有强引用时,自动删除该元素。

对不可变对象的优化

不可变对象的优化
  • 使用一个元组创建另外一个元组(tuple()、[:]、copy、deepcopy),
    得到的是同一个对象。
  • 共享字符串字面量是一种优化措施,称为「驻留 interning」
  • 类似的还有 bytes、frozenset 实例、较小的整数,这样能节省内存,提高解释器速度。其实不了解也无伤大雅。

杂谈

  • 从 object 继承的_eq_ 方法(即 == 运算符)比较的是对象 id
  • 用户创建的类,其实例默认可变
  • 可变对象是导致多线程编程难以处理的主要原因。某个线程改动对象后,不正确同步则损坏数据,过度同步又导致死锁。
  • Python 没有手动销毁对象的机制。这是个好特性:如果能手动销毁对象,那么指向对象的强引用就不知怎么处理了。
  • CPython 中,这样写是安全的:
    open('test.txt', 'wt', encoding='utf-8').write('1, 2, 3')
    因为文件对象的引用数量在 write 方法返回后归零,销毁内存中文件对象之前,会立即关闭文件。而在 Jpython 或 IronPython 中,open().write() 却是不安全的,因为它们不依靠引用计数。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容