- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议16:分清 == 与 is 的适用场景
在判断两个字符串是否相等的时候,混用is和==是很多初学者经常犯的错误,造成的结果是程序在不同情况下表现不一。先来看一个例子:
>>> a = "Hi" >>> b = "Hi" >>> a is b True >>> a == b #is 和 == 结果一样 True >>> a1 = "I am using long string for testing" >>> b1 = "I am using long string for testing" >>> a1 is b1 #is 的结果为False False >>> a1 == b1 # == 的结果为True 。两者并不一样 True >>> str1 = "string" >>> str2 = "".join(['s','t','r','i','n','g']) >>> print str2 string >>> str1 is str2 False >>> str1 == str2 #== 和is 的结果在这种情况下也不一样 True
造成这种奇怪现象的原因是什么呢?为什么在有些情况下is和==输出相同而在有些情况下又不相同呢?我们来分析一下:首先通过id()函数来看看这些变量在内存中具体的存储空间,为了方便讨论问题,用表2-1来表示上例具体结果。
表2-1 不同变量组id()以及is和==的求值结果
从表格中可以清晰地看到,is和==在验证两个字符串是否相等的时候表现确实不一致,显然混用或者将它们等同起来是存在风险的。那么字符串的比较到底是用is还是用==呢?先来看看Python官方文档中对这两种操作的如下表2-2所示。
表2-2 两种操作的意义
is表示的是对象标示符(object identity),而==表示的意思是相等(equal),显然两者不是一个东西。实际上,造成上面输出结果不一致的根本原因在于:is的作用是用来检查对象的标示符是否一致的,也就是比较两个对象在内存中是否拥有同一块内存空间,它并不适合用来判断两个字符串是否相等。x is y仅当x和y是同一个对象的时候才返回True,x is y 基本相当于id(x) == id(y)。而==才是用来检验两个对象的值是否相等的,它实际调用内部__eq__()方法,因此a == b相当于a.__eq__(b),所以==操作符是可以被重载的,而is不能被重载。一般情况下,如果x is y为True的话x == y的值也为True(特殊情况除外,如NaN,a = float('NaN');a is a 为True,a==a为false),反之则不然。
弄清楚了is和==之间的区别,再来看上述表格中的输出也就不难理解了。但如果再细心一点也许会发现第1组(标注①)中a和b的id值一样,也就是说它们在内存中是同一个对象,而第二组(标注②)中a1和b1的id值却不一样。这又是为什么呢?这是Python中的string interning(字符串驻留)机制所决定的:对于较小的字符串,为了提高系统性能会保留其值的一个副本,当创建新的字符串的时候直接指向该副本即可。因此标注①中“Hi”在系统内存中实际上只有一个副本,所以a和b的id值是一样的;而标注②中a1和b1是长字符串,并不会驻留,Python内存中各自创建了对象来表示a1和b1,这两个对象拥有相同的内容但对象标示符却不相同,所以==的值为True而is的值为False。
注意
判断两个对象相等应该使用==而不是is。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论