Chapter 3
第3章Python进阶
章节主张
第3章Python进阶这一章真正要建立的,不是孤立知识点,而是围绕“迭代器、生成器与装饰器是表达能力升级、环境与工具链先于语法细节、函数与模块是从会写到会组织的分水岭”形成一套能反复练习、能迁移到真实任务里的 Python 学习路径。
中文释读
读 第3章Python进阶 时,不要只把它当作语法或模块说明书。更有价值的读法,是问自己:这一章解决了我在编程、科学计算或数据分析流程中的哪个瓶颈?
这本书的强项在于把工具、基础语法、科学计算库和案例工作流连成一条线。章节页因此会把原书内容翻译成“知识点 -> 操作动作 -> 易错边界 -> 迁移练习”的学习结构。
本章知识路线
关键论据
- 函数是Python的核心,能够提高代码的复用率。
- 为了更好地使用函数,有必要了解函数的一些运行机制和高级用法。
- 1.参数的传递机制 在Python中,函数参数的传递机制跟赋值机制一样,其本质都是共用内存地址,并不会真正复制对象。
- 引用传递 (Call By Reference)模式指的是函数在调用过程中,参数与实际传入的对象共享同一块内存地址。
- 为了进一步理解引用传递的本质,定义如下函数: 对于给定的参数x,该函数返回参数x对应的内存地址。
行动清单
- 先用最小代码样例跑通本章核心知识点。
- 把本章知识点接到一个真实小任务上,而不只停留在示例。
- 记录本章最容易报错的边界条件和调试方式。
- 复盘:这一章内容如何进入自己的长期 Python 学习系统。
本章图版学习路径
图版按知识点分组,适合拿来做复现、迁移和复盘练习,不只是“看一眼效果”。
源章节深读
3.1 函数进阶
这节解决什么问题:这节要解决的不是背下“3.1 函数进阶”,而是把这个知识点放进真正可运行、可调试、可迁移的 Python 学习流程里。
怎么用到自己的系统:把它写进自己的学习系统:先用最小例子跑通,再把“3.1 函数进阶”迁移到一个实际小任务中,最后记录哪些边界条件最容易报错。
常见错误:常见误区是只记住 API 或代码片段,却没理解 3.1 函数进阶 背后的对象模型、输入输出和适用边界。
函数是Python的核心,能够提高代码的复用率。为了更好地使用函数,有必要了解函数的一些运行机制和高级用法。 1.参数的传递机制 在Python中,函数参数的传递机制跟赋值机制一样,其本质都是共用内存地址,并不会真正复制对象。这种共享内存的方式叫作引用传递。 引用传递 (Call By Reference)模式指的是函数在调用过程中,参数与实际传入的对象共享同一块内存地址。 为了进一步理解引用传递的本质,定义如下函数: 对于给定的参数x,该函数返回参数x对应的内存地址。将该函数作用在数字上: 函数f(a)的返回值与a的内存地址是一致的。这表示,当函数f()被调用时,Python并没有将a的值复制一份传给参数x,而是让参数x与a共享了同一块内存。换句话说,x和a是同一个对象。再将函数作用在列表上,得到类似的结论: 这种共享同一个对象的机制意味着,可以在函数中修改传入参数的值。例如,定义这样的一个函数,对于参数x,让x[0]变为999,并返回修改后的x: 对列表c应用这个函数,Python会先让x指向c所在的内存。由于x和c共享同一个对象,修改x[0]会让c的值相应改变: 不过,如果在函数中给参数x赋了一个新值(如另一个列表),根据赋值机制,虽然x指向一个新的内存位置,但原来的变量不会改变: 2.默认参数的传递 有默认参数的情况下,Python会在函数定义时预先为默认参数分配内存,每次调用默认参数时,Python会从这个预先分配好的内存地址得到这个默认参数,以避免每次生成一个额外的默认参数。这样做能够节约一定的内存空间,不过也可能会得到一些与直觉不符的结果。例如,考虑这样的函数f,该函数接受一个参数x,该参数的默认值为空列表: 如果不给f传递参数,直觉上它应该返回列表[1]。但实际上,由于默认参数的
3.2 迭代器与生成器
这节解决什么问题:这节要解决的不是背下“3.2 迭代器与生成器”,而是把这个知识点放进真正可运行、可调试、可迁移的 Python 学习流程里。
怎么用到自己的系统:把它写进自己的学习系统:先用最小例子跑通,再把“3.2 迭代器与生成器”迁移到一个实际小任务中,最后记录哪些边界条件最容易报错。
常见错误:常见误区是只记住 API 或代码片段,却没理解 3.2 迭代器与生成器 背后的对象模型、输入输出和适用边界。
迭代器与生成器是Python中for循环机制的重要组成部分,了解迭代器与生成器的原理,能帮助读者更好地理解for循环背后的实现原理。 1.迭代器的规则 Python中的容器类型通常包含一个 迭代器 (Iterator)来帮助它们支持for循环的操作。这些容器类型需要实现一个.__iter__()方法返回相应的迭代器: 拥有迭代器方法的对象也被称为一个 可迭代对象 (Iterable Object)。常见的容器类型(如列表、集合、字典、元组等)都有一个对应的迭代器: 迭代器对象支持.__next__()方法,.__next__()方法返回容器中被迭代到的下一个元素。例如,对于列表的迭代器对象: 第一次调用.__next__()方法时,返回第一个元素2: 再次调用.__next__()方法时,返回可迭代对象的下一个元素: 也可以调用Python自带的next()函数来获得可迭代对象的下一个元素: Python 2与Python 3的区别之迭代器的.__next__()方法 :Python 2中,迭代器的下一个元素使用.next()方法调用;Python 3中,迭代器则改用.__next__()方法获取下一个元素。 迭代器是一种一次性消费品,迭代完最后一个元素后,调用.__next__()方法不会回到开头,而是抛出一个StopIteration异常: for循环的运作正是利用了迭代器的这种性质。循环一个容器类型时,Python首先使用它的.__iter__()方法得到它的迭代器,然后不断调用迭代器的.__next__()方法,在抛出StopIteration异常后停止循环。 迭代器对象本身也有一个.__iter__()方法,这个方法必须返回迭代器本身: 在Python中,有一些函数返回的结果是迭代器对
3.3 装饰器
这节解决什么问题:这节要解决的不是背下“3.3 装饰器”,而是把这个知识点放进真正可运行、可调试、可迁移的 Python 学习流程里。
怎么用到自己的系统:把它写进自己的学习系统:先用最小例子跑通,再把“3.3 装饰器”迁移到一个实际小任务中,最后记录哪些边界条件最容易报错。
常见错误:常见误区是只记住 API 或代码片段,却没理解 3.3 装饰器 背后的对象模型、输入输出和适用边界。
装饰器是一种输出另一个函数的函数,了解装饰器的调用与生成机制,能够帮助读者更好地理解和使用函数的高级功能。 在介绍装饰器之前,需要先回顾函数的一些基本性质。在Python中,函数本身就是一个对象: 函数可以作为一个参数传给另一个函数: 假设有这样一个函数add(): 在调试一个复杂程序时,可能会希望在调用函数时,打印一条相关信息,以说明哪个函数被调用了。最简单的做法是在函数中直接加上一条print()函数的语句: 不过,除了add()函数,其他的函数都有这样的需求,在每个函数里都加上一行print()函数显得比较麻烦。为此,对于这类公共的功能,可以考虑使用一个公共函数,该函数接受一个函数作为参数,并打印出这个函数相关的信息,最后返回这个函数本身。 函数的名字可以通过函数的.__name__属性获得: 利用.__name__属性,这个公共函数定义如下: 调用时,可以用loud(add)(1,2)代替add(1,2): 换一个系统自带函数作为参数,比如len()函数: 不过,这样的定义方式并不完全符合要求,因为这个语句其实是在调用loud(add)的时候打印出来的,并不是调用add()函数本身: 函数add()并没有接受参数,但信息还是被显示了。为了解决这个问题,可以利用高阶函数的特性,在函数中定义新函数,并将打印信息的功能放到一个内部函数中: 如果只是调用loud_info(add)而不传入参数,并不会打印相关信息: 传入参数时,打印信息: 在Python中,像loud_info()这种为接受函数作为参数,为函数添加新特性的函数,一般称为 装饰器 (Decorator)。在实际应用中,把函数f的每个调用都改成loud_info(f)显得不是很方便。为此,Python提供了“@”符号来简化装饰器的使
3.4 上下文管理器与with语句
这节解决什么问题:这节要解决的不是背下“3.4 上下文管理器与with语句”,而是把这个知识点放进真正可运行、可调试、可迁移的 Python 学习流程里。
怎么用到自己的系统:把它写进自己的学习系统:先用最小例子跑通,再把“3.4 上下文管理器与with语句”迁移到一个实际小任务中,最后记录哪些边界条件最容易报错。
常见错误:常见误区是只记住 API 或代码片段,却没理解 3.4 上下文管理器与with语句 背后的对象模型、输入输出和适用边界。
读者在阅读Python代码时,有时会遇到类似with开头的语句,特别是在文件读写的情况下。with语句对应于Python中的上下文管理器机制,通常用于资源的读取与释放。 在文件读写时,如果一个文件被打开,且未被正常关闭,可能会出现一些意想不到的结果。写入文件时,如果文件没有被正常关闭,会导致某些内容没有来得及写入的情况。例如,用一个循环向文件中写入数据: 当i循环到500的时候抛出了一个ZeroDivisionError异常,程序中断,上一行应该执行了写入“line 500”的操作,但打开文件可能会发现不符合预期的结果。对于上面的情况,可以采用try块的方式,在finally中确保文件f被正确关闭: finally能够保证f.close()都会被正常执行。打开文件会发现,文件的结尾保存的是正常的结果: 不仅仅是文件,在Python处理各种资源时,都可能会遇到这样的问题,这些资源包括文件、线程、数据库、网络连接等。资源使用的问题十分常见,都使用try块处理显得不够简洁。为此,Python提供了上下文管理器的机制来解决这个问题,它通常与关键字with一起使用。对于上面的例子,用with语句调用的方式为: 这与使用try块的效果相同,但是简洁了许多。 1.基本形式和with语句 with语句的基本用法如下: 其中,<expression>是一个上下文管理器。 上下文管理器 (Context Manager)是一个实现了.__enter__()方法和.__exit__()方法的对象。文件对象包含这两个方法,所以是一个合法的上下文管理器,可以用在with语句中: 在with语句中,上下文管理器的.__enter__()方法会在<statements>执行前执行,而.__exit__()方法会在<state
3.5 变量作用域
这节解决什么问题:这节要解决的不是背下“3.5 变量作用域”,而是把这个知识点放进真正可运行、可调试、可迁移的 Python 学习流程里。
怎么用到自己的系统:把它写进自己的学习系统:先用最小例子跑通,再把“3.5 变量作用域”迁移到一个实际小任务中,最后记录哪些边界条件最容易报错。
常见错误:常见误区是只记住 API 或代码片段,却没理解 3.5 变量作用域 背后的对象模型、输入输出和适用边界。
函数外部定义的变量可以在函数里面使用、修改和重新赋值,这涉及Python中变量作用域的问题。 变量作用域 (Variable Scope)是指变量的有效生存空间。 在函数中,Python会按照以下顺序,在各个作用域的命名空间中寻找变量: ●函数局部作用域 (Local Function Scope)。 ●闭包作用域 (Enclosing Scope)。 ●全局作用域 (Global Scope)。 ●内置作用域 (Built-in Scope)。 如果有重名的变量,局部作用域优先于闭包作用域,闭包作用域优先于全局作用域,全局作用域优先于内置作用域。函数局部作用域是函数内部的作用域,例如: 在这个foo()函数中,所有的变量都在这个函数的局部作用域中。函数局部作用域中的变量离开了这个函数就不起作用了,因此,不能在函数外面调用foo()函数里面的变量c。 全局作用域指的是函数外面所定义的变量,例如: 变量c在全局作用域定义,在foo()函数里被使用。对于一个全局变量,如果在函数内部对它重新赋值,它会被认为是一个局部变量: 在这个例子中,函数中的c是一个局部变量,它与全局中的变量c不同,也不会影响全局变量c的值。如果想在函数中对全局变量重新赋值,可以使用关键字global。例如,在函数中加入global c: 加了global关键词之后,c的值在foo()中被改变了,所以现在c的值是2。如果不加global,Python会在局部作用域中定义变量c,全局的c仍然是1: 在Python中,只要变量被使用了,它的值就会存在于当前的作用域而不会消失,即使变量在循环语句或者判断语句中定义。例如,执行这个循环之后: 当前的作用域中会存在: ●变量i,值为9,因为for循环最后一个迭代的值是9。 ●变量j,值为Tr
3.6 本章学习笔记
这节解决什么问题:这节要解决的不是背下“3.6 本章学习笔记”,而是把这个知识点放进真正可运行、可调试、可迁移的 Python 学习流程里。
怎么用到自己的系统:把它写进自己的学习系统:先用最小例子跑通,再把“3.6 本章学习笔记”迁移到一个实际小任务中,最后记录哪些边界条件最容易报错。
常见错误:常见误区是只记住 API 或代码片段,却没理解 3.6 本章学习笔记 背后的对象模型、输入输出和适用边界。
本章对Python的一些进阶用法进行了介绍。掌握Python的进阶用法可以帮助读者更好地理解代码,提高Python编程的能力和水平。 学完本章,读者应该做到: ●知道函数作为对象、作为参数、作为返回值的一些用法。 ●掌握函数map()和filter()以及Lambda表达式的使用。 ●知道并掌握迭代器和生成器的原理和使用。 ●知道并掌握装饰器的原理和使用。 ●知道上下文管理器的原理和构造,掌握with语句的使用。 ●知道各个作用域的概念,并掌握变量在不同作用域下的使用逻辑。 1.本章新术语 本章涉及的新术语见表3-1。 表3-1 本章涉及的新术语 2.本章新函数 本章涉及的新函数见表3-2。 表3-2 本章涉及的新函数 3.本章Python 2与Python 3的区别 本章涉及的Python 2与Python 3的区别见表3-3。 表3-3 本章涉及的Python 2与Python 3的区别
辨析题:如果你只会照抄 第3章Python进阶 里的例子,却无法换一个输入自己写出来,真正缺的是什么?
多数时候缺的不是记忆,而是对象模型、输入输出边界和操作顺序的理解。把知识点换到新输入上依然能运行,才算真的进入了自己的系统。