CS61A-2

敖炜 Lv5

定义新函数

  1. 当调用用户定义的函数时
    1. 添加一个local frame,形成一个新环境
    2. 将函数的形参与那个frame中的参数绑定
    3. 在新环境中执行函数体
  2. def语句和赋值语句都将名称绑定到值,并且任何现有的绑定都会丢失

环境

  1. 环境图是跟踪python解释器执行我们键入的程序时发生的情况的一种方式。环境图可以可视化解释器的过程
  2. 环境是真实的事物:它们是编程语言的解释器跟踪名称匹配的方式。是一种追踪名称和值之间绑定的内存
  3. 在一个框架内,名称不能重复,它最多只能绑定到一个值
  4. 赋值语句的执行规则
    1. 从左到右执行等号右边的所有表达式
    2. 在当前frame中,将所有结果值的名称绑定到等号右侧的名称
  5. 计算表达式的环境由一系列组成。每个帧包含绑定
    • 只有一个全局帧
    • 赋值和导入语句将条目添加到当前环境的第一帧

调用用户定义函数

  1. 调用用户定义函数将引入了一个只能被那个函数访问的本地帧。为将用户定义的函数应用到一些参数上
    • 在新的本地帧中将参数与函数形参的名字绑定
    • 在以这个帧开始的环境中执行函数体
    • 每一个函数调用都有一个新的本地帧
    • 函数体直到调用时才被执行,在定义时不执行
    • “返回值”不是名称绑定

例子:调用一个用户定义函数


本地名称

  1. 函数的含义应该独立于其作者选择的参数名称

选择名称

  1. 函数名称小写,单词之间用下划线分隔。鼓励使用描述性名称
  2. 函数名称通常会描述解释器对参数应用的操作或结果的名称
  3. 参数名称是小写的,单词之间用下划线分隔。首选单字名称
  4. 参数名称应该描述参数在函数中起的作用,不单是参数的类型
  5. 当作用明显时,可以使用单字母参数名称,但应避免使用“l”(小写 ell)、“O”(大写 oh)或“I”(大写 i),以避免与数字混淆。

函数抽象

  1. 函数定义应该能够抑制细节。该函数的用户可能自己没有编写该程序,而是可能从另一个程序员处以“黑匣子”的形式获得该函数。床程序员不需要知道该函数是如何实现的,但是可以使用它
  2. 功能抽象的各个方面。要掌握函数抽象的使用,要考虑它的三个核心属性
    • 函数的域:可采用的参数集
    • 函数的范围:可返回的值的集合
    • 函数的目的:输入和输出之间的关系(以及可能产生的任何副作用)

运算符

  1. 如果使用python -m doctest xx.py测试时,若按照doctest执行,则无特殊输出。如果想要查看更多输出,可以使用-v选项,将会显示发生的一切
  2. 定义函数时,可以为形参指定默认值,这不是赋值语句。相反,这是放在形参后面的默认值的占位符

设计函数

  1. 好的函数的品质
    • 每个函数都应该只有一项工作。该工作应该可以通过一个简短的名称来识别,并且可以用一行文本来描述。依次执行多项作业的函数应划分为多个函数
    • Don’t repeat yourself是软件工程的核心原则。所谓DRY原则是指多个代码片段不应描述冗余逻辑。相反,该逻辑应该只实现一次,给出一个名称,然后多次调用。如果发现自己复制并粘贴了一段代码,那么很可能已经找到了函数抽象的机会
    • 函数应该被一般性的定义

文档

  1. 函数定义通常包含描述函数的文档,称为docstring,它必须与函数体一起缩进。第一行描述该函数的工作,下面几行描述参数并阐明函数的行为
  2. 调用help函数,并以函数名作为参数时,将会显示文档
  3. 注释。注释可以附加到“#”后面

默认参数值

  1. 函数体中使用的大多数形参应该有默认值。一些永不改变的值(如基本常数),可以绑定在函数体或全局帧中

控制

复合语句

  1. 简单语句是不以冒号结尾的单行。复合语句以一个冒号结尾的单行标题开始,分隔标题和缩进的语句套件一起称为子句。
  2. 缩进套件时,所有行必须以相同的方式缩进相同的量(使用空格,而不是制表符)

定义函数Ⅱ:局部赋值

  1. 赋值语句的作用是将名称绑定到当前环境的第一帧中的值。函数体内的赋值语句不能影响全局帧。函数只能操纵其本地环境这一事实对于创建模块化程序至关重要,在模块化程序中,纯函数仅通过它们获取和返回的值进行交互

条件语句

  1. 执行比较并返回布尔值的函数通常以is开头,后面不跟下划线

迭代

  1. 在更新等号左侧的任何绑定之前计算等号右侧的所有内容
  2. Ctrl+C强制Python停止循环

测试

  1. 测试函数是验证函数的行为是否符合预期的行为
  2. 测试通常采用另一个函数的形式,其中包含对正在测试的函数的一个或多个示例调用,然后根据预期结果验证返回的值。与大多数通用函数不同,测试涉及选择和验证具有特定参数值的调用。测试也可用作文档:它们演示如何调用函数以及哪些参数值是合适的
  3. 断言。程序员使用断言语句来测试期望,例如正在测试的函数的输出。断言语句在布尔上下文中有一个表达式,后跟带引号的文本行(单引号或双引号都可以,但要一致),如果布尔表达式计算结果为假,则将显示该文本行
    1
    >>> assert fib(8) == 13, "第八个斐波那契数应该是13"
    当被断言的表达式的计算结果为真,执行断言语句不起作用。当为假,断言会导致错误并停止执行
  4. 在文件中而不是直接在解释器中编写python时,测试通常编写在同一文件或后缀为_test.py的相邻文件中
  5. 文档测试:前文已写。为验证单个函数的doctest交互
    可使用testmod函数
    1
    2
    >>> from doctest import testmod
    >>> testmod()
    run_docstring_examples函数,第一个参数是要测试的函数,第二个应该始终是表达式globals()的结果(这是一个返回全局环境的内置函数),第三个参数True表示我们想要的“详细”输出
    1
    2
    >>> from doctest import run_docstring_examples
    >>> run_docstring_examples(xx, globals(), xx)
    当函数的返回值与预期结果不匹配时,该函数会将此问题报告为测试失败。
  6. 有效测试的关键是在实现新功能后立即编写(并运行)测试。在实现之前编写一些测试甚至是一个很好的做法,以便在您的脑海中记住一些示例输入和输出。应用单个功能的测试称为单元测试。详尽的单元测试是良好程序设计的标志。
  • 标题: CS61A-2
  • 作者: 敖炜
  • 创建于 : 2023-07-05 21:44:16
  • 更新于 : 2024-04-19 09:31:15
  • 链接: https://ao-wei.github.io/2023/07/05/CS61A-2/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论