fluent python-第 8 章 面向对象惯用法

爱丽丝和白骑士为本章要讨论的内容定了基调。 本章的主题是对象与对象名称之间的区别。 名称不是对象, 而是单独的东西.


8.1 变量不是盒子

In [431]: a = [1,2,3]                         # 第一次测试
In [432]: b = a
In [433]: a.append(4)   # a.append并未改变 a 的地址

In [434]: b             # 所以此时 id()可以测试出 a,b地址不变
Out[434]: [1, 2, 3, 4]

In [435]: a = [1,2,3]                         # 第二次测试
In [436]: b = a
In [437]: a += [4,5]    # 同理,地址不变

In [438]: b
Out[438]: [1, 2, 3, 4, 5]

In [439]: a = [1,2,3]                         # 第三次测试
In [440]: b = a
In [441]: a = a + [4,5]    # a 已经发生了变化

In [442]: a
Out[442]: [1, 2, 3, 4, 5]
In [443]: b
Out[443]: [1, 2, 3]


8.2.2 元组的相对不可变性

元组与多数 Python 集合( 列表、 字典、 集, 等等) 一样, 保存的是对象的引用。 如果引用的元素是可变的, 即便元组本身不可变, 元素依然可变。 也就是说, 元组的不可变性其实是指 tuple 数据结构的物理{ 而 str、 bytes 和 array.array 等单一类型序列是扁平的, 它们保存的不是引用, 而是在连续的内存中保存数据本身( 字符、 字节和数字) }1容( 即保存的引用) 不可变, 与引用的对象无关。

>>> t1 = (1, 2, [30, 40])      ➊  t1 不可变, 但是 t1[-1] 可变。
>>> t2 = (1, 2, [30, 40]) ➋
>>> t1 == t2 ➌
True
>>> id(t1[-1]) ➍
4302515784
>>> t1[-1].append(99) ➎
>>> t1
(1, 2, [30, 40, 99])
>>> id(t1[-1]) ➏
4302515784
>>> t1 == t2 ➐
False


8.3 默认做浅复制

n [470]: class Bus:
     ...:     def __init__(self, passengers=None):
     ...:         if passengers is None:
     ...:             self.passengers = []
     ...:         else:
     ...:             self.passengers = list(passengers)
     ...:     def pick(self, name):
     ...:         self.passengers.append(name)
     ...:     def drop(self, name):
     ...:         self.passengers.remove(name)
     ...:

In [471]: car = Bus()

In [472]: car.passengers
Out[472]: []

In [473]: car.pick('lily')

In [474]: car.pick('jack')

In [475]: car.passengers
Out[475]: ['lily', 'jack']

接下来,我们将创建一个 Bus 实例( bus1) 和两个副本, 一个是浅复制副本( bus2) , 另一个是深复制副本( bus3) , 看看在 bus1 有学生下车后会发生什么:

>>> import copy
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
>>> bus2 = copy.copy(bus1)
>>> bus3 = copy.deepcopy(bus1)
>>> id(bus1), id(bus2), id(bus3)
(4301498296, 4301499416, 4301499752) ➊
>>> bus1.drop('Bill')
>>> bus2.passengers
['Alice', 'Claire', 'David'] ➋
>>> id(bus1.passengers), id(bus2.passengers), id(bus3.passengers)
(4302658568, 4302658568, 4302657800) ➌
>>> bus3.passengers
['Alice', 'Bill', 'Claire', 'David'] ➍

❶ 使用 copy 和 deepcopy, 创建 3 个不同的 Bus 实例。
❷ bus1 中的 'Bill' 下车后, bus2 中也没有他了。
❸ 审查 passengers 属性后发现, bus1 和 bus2 共享同一个列表对
象, 因为 bus2 是 bus1 的浅复制副本。
❹ bus3 是 bus1 的深复制副本, 因此它的 passengers 属性指代另一
个列表。


8.4 函数的参数作为引用时

Python 唯一支持的参数传递模式是共享传参( call by sharing) 。共享传参指函数的各个形式参数获得实参中各个引用的副本。 也就是说, 函数内部的形参是实参的别名.
这种方案的结果是, 函数可能会修改作为参数传入的可变对象, 但是无法修改那些对象的标识( 即不能把一个对象替换成另一个对象) 。 示例中有个简单的函数, 它在参数上调用 += 运算符。 分别把数字、 列表和元组传给那个函数, 实际传入的实参会以不同的方式受到影响

>>> def f(a, b):
... a += b
... return a
...
>>> x = 1
>>> y = 2
>>> f(x, y)
3
>>> x, y ➊
(1, 2)
>>> a = [1, 2]
>>> b = [3, 4]
>>> f(a, b)
[1, 2, 3, 4]
>>> a, b ➋       # 列表 a 变了。
([1, 2, 3, 4], [3, 4])
>>> t = (10, 20)
>>> u = (30, 40)
>>> f(t, u)
(10, 20, 30, 40)
>>> t, u ➌       # 元组 t 没变。
((10, 20), (30, 40))


8.5 del和垃圾回收

对象绝不会自行销毁; 然而, 无法得到对象时, 可能会被当作垃圾
回收 —— Python 语言参考手册中“Data Model”一章

del 语句删除名称, 而不是对象。 del 命令可能会导致对象被当作垃圾回收, 但是仅当删除的变量保存的是对象的最后一个引用, 或者无法得到对象时。 重新绑定也可能会导致对象的引用数量归零, 导致对象被销毁。

为了演示对象生命结束时的情形, 示例使用 weakref.finalize 注册一个回调函数, 在销毁对象时调用

>>> import weakref
>>> s1 = {1, 2, 3}
>>> s2 = s1 ➊
>>> def bye(): ➋
... print('Gone with the wind...')
...
>>> ender = weakref.finalize(s1, bye) ➌
>>> ender.alive ➍
True
>>> del s1
>>> ender.alive ➎
True
>>> s2 = 'spam' ➏
Gone with the wind...
>>> ender.alive
False

❶ s1 和 s2 是别名, 指向同一个集合, {1, 2, 3}。
❷ 这个函数一定不能是要销毁的对象的绑定方法, 否则会有一个指向
对象的引用。
❸ 在 s1 引用的对象上注册 bye 回调。
❹ 调用 finalize 对象之前, .alive 属性的值为 True。
❺ 如前所述, del 不删除对象, 而是删除对象的引用。
❻ 重新绑定最后一个引用 s2, 让 {1, 2, 3} 无法获取。 对象被销毁
了, 调用了 bye 回调, ender.alive 的值变成了 False。


8.8 本章小结

每个 Python 对象都有标识、 类型和值。 只有对象的值会不时变化。

杂谈

平等对待所有对象
发现 Python 之前, 我学过Java。 我一直觉得 Java 的 == 运算符用着不舒服。 程序员关注的基本上是相等性, 而不是标识, 但是 Java的 == 运算符比较的是对象( 不是基本类型) 的引用, 而不是对象的值。

Python 采取了正确的方式。 == 运算符比较对象的值, 而 is 比较引用。 此外, Python 支持重载运算符, == 能正确处理标准库中的所有对象, 包括 None——这是一个正常的对象, 与 Java 的 null 不同。

In [480]: a = [1,2]

In [481]: b = [1,2]

In [482]: a == b
Out[482]: True

In [483]: a is b
Out[483]: False

In [484]: id(a)
Out[484]: 4564461576

In [485]: id(b)
Out[485]: 4547337032
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,518评论 1 51
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,209评论 9 118
  • 写在前面 如非特别说明,下文均基于Python3 1、一切皆对象 Python哲学: Python中一切皆对象 1...
    理查德成阅读 1,066评论 1 8
  • 个人笔记,方便自己查阅使用 Py.LangSpec.Contents Refs Built-in Closure ...
    freenik阅读 67,704评论 0 5
  • 嗨,各位! 我又非准时准点的出现了,这一次总彩铅画的是鹿晗,不知道这里有没有鹿晗的小迷妹啊? 有的话点个小心心❤️...
    喃七月阅读 1,048评论 24 15