首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
第7章 编程术语
7.1 编程术语定义
7.1.1 作为语言的Python和作为解释器的Python
7.1.2 垃圾回收
7.1.3 字面量
7.1.4 关键字
7.1.5 对象、值、实例和身份
7.1.6 项
7.1.7 可变和不可变
7.1.8 索引、键和哈希值
7.1.9 容器、序列、映射和集合类型
7.1.10 特殊方法
7.1.11 模块和包
7.1.12 可调用对象和头等对象
7.2 经常被混淆的术语
7.2.1 语句和表达式
7.2.2 块、子句和主体
7.2.3 变量和特性
7.2.4 函数和方法
7.2.5 可迭代对象和迭代器
7.2.6 语法错误、运行时错误和语义错误
7.2.7 形参和实参
7.2.8 显式类型转换和隐式类型转换
7.2.9 属性和特性
7.2.10 字节码和机器码
7.2.11 脚本和程序,以及脚本语言和编程语言
7.2.12 库、框架、SDK、引擎、API
第8章 常见的Python陷阱
8.1 循环列表的同时不要增删其中的元素
8.2 复制可变值时务必使用copy.copy()和copy.deepcopy()
8.3 不要用可变值作为默认参数
8.4 不要通过字符串连接创建字符串
8.5 不要指望sort()按照字母顺序排序
8.6 不要假设浮点数是完全准确的
8.7 不要使用链式!=运算符
8.8 不要忘记在仅有一项的元组中添加逗号
第9章 Python的奇特难懂之处
9.1 为什么256 是256,而257 不是257
9.2 字符串驻留
9.3 假的Python 增量运算符和减量运算符
9.4 传递空列表给all()
9.5 布尔值是整数值
9.6 链式使用多种运算符
9.7 Python 的反重力特性
当前位置:
首页>>
技术小册>>
Python编程轻松进阶(三)
小册名称:Python编程轻松进阶(三)
### 第8章 常见的Python陷阱 在Python编程的旅途中,即使是经验丰富的开发者也难免会遇到一些令人困惑或意外的情况,我们称之为“陷阱”。这些陷阱往往源自于Python语言设计的灵活性、动态类型系统、以及Pythonic哲学中的一些微妙之处。了解并避免这些陷阱,对于提升代码质量、减少调试时间以及增强编程信心至关重要。本章将深入探讨Python中一些常见的陷阱,帮助读者在进阶之路上更加稳健。 #### 8.1 可变默认参数 Python允许函数定义时包含默认参数,这在很多情况下非常有用,可以简化函数调用。然而,当默认参数是可变对象(如列表、字典、集合等)时,就可能掉入陷阱。 **陷阱示例**: ```python def add_to_list(item, my_list=[]): my_list.append(item) return my_list print(add_to_list(1)) # 输出 [1] print(add_to_list(2)) # 输出 [1, 2],而非预期中的 [2] ``` **解析**:在上面的例子中,`my_list`被设置为空列表作为默认参数。但是,Python在函数定义时只计算默认参数值一次,之后每次调用`add_to_list`时,如果未提供新的`my_list`,就会使用第一次计算得到的同一个列表。因此,列表会在多次调用间累积元素。 **解决方案**:使用`None`作为默认参数,并在函数体内检查其值,必要时创建新列表。 ```python def add_to_list(item, my_list=None): if my_list is None: my_list = [] my_list.append(item) return my_list ``` #### 8.2 列表推导式中的变量作用域 列表推导式是Python中强大的工具,但如果不理解其背后的作用域规则,可能会遇到意想不到的结果。 **陷阱示例**: ```python x = 'global' y = [x for _ in range(5) if x := 'local'] print(x) # 输出 'local',而非 'global' ``` **解析**:在这个例子中,使用了海象运算符(`:=`)在列表推导式内部为`x`赋了新值。然而,这里的`x`实际上是在列表推导式的局部作用域内被重新绑定,而不是修改全局变量`x`。这导致全局变量`x`的值在列表推导式执行后被更改为`'local'`。 **注意**:这种用法通常不是推荐的做法,因为它可能导致代码难以理解和维护。 #### 8.3 字符串与字节串混淆 Python中字符串(`str`)和字节串(`bytes`)是两种不同的数据类型,分别用于处理文本和二进制数据。混淆两者常常导致错误。 **陷阱示例**: ```python s = "hello world" b = s.encode('utf-8') # 编码为字节串 print(b + "!") # TypeError: can only concatenate str (not "bytes") to str ``` **解析**:尝试将字节串`b`与字符串`"!"`进行拼接时,Python会抛出`TypeError`,因为两者类型不兼容。 **解决方案**:确保在拼接前将两者转换为相同类型,或者明确使用合适的方法处理。 ```python print(b + b'!') # 字节串拼接 # 或者 print(s + "!") # 字符串拼接 ``` #### 8.4 相等性检查与身份检查混淆 在Python中,`==`用于检查两个对象的值是否相等,而`is`用于检查两个对象是否是同一个对象(即身份是否相同)。 **陷阱示例**: ```python a = [1, 2, 3] b = [1, 2, 3] print(a == b) # True,因为内容相同 print(a is b) # False,因为不是同一个对象 ``` **解析**:即使两个列表内容完全相同,它们也不是同一个对象,因此`is`比较会返回`False`。 **陷阱加深**: 对于小整数和短字符串,Python实现了对象池(interning)机制,这意味着某些范围内的整数和字符串可能会共享同一个对象。 ```python x = 256 y = 256 print(x is y) # 可能为True,因为Python实现可能缓存了这些小整数 s1 = "hello" s2 = "hello" print(s1 is s2) # True,字符串字面量通常会被缓存 ``` #### 8.5 闭包中的变量绑定 闭包是Python中一个强大的特性,允许函数访问并操作函数外部的变量。然而,如果不小心,闭包中的变量可能会以你意想不到的方式被绑定。 **陷阱示例**: ```python def create_multipliers(): multipliers = [] for i in range(5): def multiplier(x): return x * i multipliers.append(multiplier) return multipliers funcs = create_multipliers() for func in funcs: print(func(2)) # 预期是0, 2, 4, 6, 8,但实际上是10, 10, 10, 10, 10 ``` **解析**:这里的问题是,当`multiplier`函数被创建时,它并没有捕获`i`的当前值,而是捕获了对`i`的引用。当`for`循环结束时,`i`的值是4,因此所有闭包中的`i`都指向了同一个值(4),最终都返回了`2 * 4 = 8`。 **解决方案**:使用默认参数技巧来“冻结”`i`的值。 ```python def create_multipliers(): multipliers = [] for i in range(5): def multiplier(x, i=i): # 注意这里i=i的用法 return x * i multipliers.append(multiplier) return multipliers ``` #### 8.6 总结 Python的灵活性和动态特性为编程带来了极大的便利,但同时也隐藏着一些不易察觉的陷阱。了解并避免这些陷阱,对于写出健壮、可维护的代码至关重要。本章通过介绍可变默认参数、列表推导式中的变量作用域、字符串与字节串混淆、相等性检查与身份检查混淆、以及闭包中的变量绑定等常见陷阱,帮助读者在Python编程进阶之路上更加稳健前行。记住,实践是检验真理的唯一标准,多写代码、多调试、多思考,是避免陷阱、提升技能的有效途径。
上一篇:
7.2.12 库、框架、SDK、引擎、API
下一篇:
8.1 循环列表的同时不要增删其中的元素
该分类下的相关小册推荐:
Python高并发编程与实战
Python合辑7-集合、列表与元组
Python合辑10-函数
Python合辑4-130个字符串操作示例
Python面试指南
Python爬虫入门与实战开发(下)
Python神经网络入门与实践
Python3网络爬虫开发实战(上)
Python合辑14-面向对象编程案例(下)
Python机器学习基础教程(下)
Python与办公-玩转PPT
Python编程轻松进阶(五)