Fluent Python 3函数 4面向对象惯用法

目录

 

1.== 和 is

2.元组的相对不可变性

3.默认做浅复制

4.函数的参数作为引用时

4.1 不要使用可变类型作为参数的默认值

4.2 防御可变参数

5 del 语句和垃圾回收 

6 弱引用

6.1 WeakValueDictionary

6.2 弱引用的局限

7 Python对不可变类型施加的把戏


1.== 和 is

每个变量都有标识、类型和值。对象一旦创建,它的标识绝不会变。可以把标识理解为对象在内存中的地址。只有对象的值会不时变化。

变量保存的是引用,这一点对 Python 编程有很多实际的影响,影响有:

#1 简单的赋值不创建副本。 对 += 或 *= 所做的增量赋值来说,如果左边的变量绑定的是不可变对象,会创建新对象;

#2 如果是可变对象,会就地修改。 为现有的变量赋予新值,不会修改之前绑定的变量。这叫重新绑定:

#3 现在变量绑定了其他对象。如果变量是之前那个对象的最后一个引用,对象会被当作垃圾回收。 函数的参数以别名的形式传递,这意味着,函数可能会修改通过参 数传入的可变对象。这一行为无法避免,除非在本地创建副本,或者使用不可变对象(例如,传入元组,而不传入列表)。

#4 使用可变类型作为函数参数的默认值有危险,因为如果就地修改了 数,默认值也就变了,这会影响以后使用默认值的调用。

 

is 运算符比较两个对象的标识;id() 函数返回对象标识的整数表示。在 CPython 中,id() 返回对象的内存地址。标识最常使用 is 运算符检查,而不是直接比较 ID。

== 运算符比较两个对象的值(对象中保存的数据), is 比较对象的标识。

通常,我们关注的是值,而不是标识,因此 Python 代码中 == 出现的频率比 is 高。

is 运算符比 == 速度快,因为它不能重载,所以 Python 不用寻找并调用特殊方法,而是直接比较两个整数 ID。

a == b 是语法糖,等同于 a.__eq__(b)。多数内置类型使用更有意义的方式覆盖了 __eq__ 方法,考虑对象属性的值。

2.元组的相对不可变性

元组与多数 Python 集合(列表、字典、集,等等)一样,保存的是对象的引用。

元组的不可变性其实是指 tuple 数据结构的物理内容(即保存的引用)不可变,与引用的对象无关。

不可变容器对象包含的对象集是不会改变的,但如果包含了对可变对象的引用,当后者的值改变时,该不可变容器对象的值也改变了。(不可变 ≠ 值不能变)

3.默认做浅复制

Python的浅层和深层复制

注意可以使用构造方法 list()、 [:]、copy.copy()进行浅层复制操作,但赋值语句增加对象的别名,指向的是同一个对象。

>>> s1 = {1, 2, 3}

>>> s2 = s1
>>> s2 is s1
True
>>> s3 = list(s1)

>>> s3 is s1
False

4.函数的参数作为引用时

Python 唯一支持的参数传递模式是共享传参(call by sharing),共享传参指函数的各个形式参数获得实参中各个引用的副本(即函数内部的形参是实参的别名),多数面向对象语言都采用这一模式。

示例:

>>> def s(a,b):
	a += b
	return a

>>> t1 = (1,2)
>>> t2 = (3,4)
>>> l1 = [1,2]
>>> l2 = [3,4]

>>> s(t1,t2)
(1, 2, 3, 4)
>>> s(l1,l2)
[1, 2, 3, 4]

>>> print(t1,t2,l1,l2)
(1, 2) (3, 4) [1, 2, 3, 4] [3, 4]

元组作为参数传给函数,之后元组的值没变;列表作为参数传给函数,之后列表的值发生变化。

可见函数可能会修改作为参数传入的可变对象,但是无法修改那些对象的标识(即不能把一个对象替换成另一个对象)。

4.1 不要使用可变类型作为参数的默认值

默认值在定义函数时计算(通常在加载模块时),因此默认值变成了函数对象的属性。因此,如果默认值是可变对象,而且修改了它的值,那么后续的函数调用都会受到影响

# 此节具体内容已省略

4.2 防御可变参数

通常使用 None 作为接收可变值的参数的默认值,__init__ 方法检查该参数的值是不是 None,如果是就赋值一个新的空列表。

del 语句和垃圾回收 

del 语句解除该名称的绑定。名称的删除将从局部或全局命名空间中移除该名称的绑定,具体作用域的确定是看该名称是否有在同一代码块的 global 语句中出现。 如果该名称未被绑定,将会引发 NameError

在 CPython 中,垃圾回收使用的主要算法是引用计数,每个对象都会统计有多少引用指向自己。当引用计数归零时,对象立即就被销毁:CPython 会在对象上调用 __del__ 方法(如果定义了),然后释放分配给对象的内存。

CPython 2.0 增加了分代垃圾回收算法,用于检测引用循环中涉及的对象组——如果一组对象之间全是相互引用,即使再出色的引用方式也会导致组中的对象不可获取。Python 的其他实现有更复杂的垃圾回收程序,而且不依赖引用计数,这意味着,对象的引用数量为零时可能不会立即调用 __del__ 方法。

1.内存管理从硬件到软件

2.CPython

3.全局解释锁GIL

4.CPython的内存分配策略

6 弱引用

弱引用不会增加对象的引用数量。引用的目标对象称为所指对象(referent)。因此我们说,弱引用不会妨碍所指对象被当作垃圾回收。

弱引用的主要用途是实现保存大对象的高速缓存或映射,但又并希望大对象仅仅因为它出现在高速缓存或映射中而保持存活。

class weakref.ref(object[, callback])

返回对 对象 的弱引用。

6.1 WeakValueDictionary

class weakref.WeakValueDictionary([dict])

弱引用值的映射类。 当不再有对键的强引用时字典中的条目将被丢弃。

WeakValueDictionary.valuerefs()

返回包含对值的弱引用的可迭代对象。

class weakref.WeakSet([elements])

保持对其元素弱引用的集合类。 当不再有对某个元素的强引用时元素将被丢弃。

6.2 弱引用的局限

不是每个 Python 对象都可以作为弱引用的目标(或称所指对象)。基本的 list 和 dict 实例不能作为所指对象,但是它们的子类可以。

set 实例可以作为所指对象。int 和 tuple 实例不能作为弱引用的目标,甚至它们的子类也不行。 这些局限基本上是 CPython 的实现细节,在其他 Python 解释器中情况可 能不一样。

Python对不可变类型施加的把戏

本节跳过

这里讨论的是 Python 的实现细节,对 Python 用户来说没那么重要。这些细节是 CPython 核心开发者走的捷径和做的优化措施,对这门语言的用户而言无需了解,而且那些细节对其他 Python 实现可能没用,CPython 未来的版本可能也不会用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值