计算机科学与Python编程导论

angular的lib & npm link用得太郁闷,随便看点不相关的课程快乐一下。

课程资源: 课程资源
视频地址: 视频地址

视频是2016年版的,比较新,所以主要一视频为主。入门课程,看看能不能用来放松心情。

主要的教学内容:knowledge of concepts,programming skill, problem solving。

What is computation

what does a computer do

基础: 执行计算,存储结果

计算的类型: 语言内建 和 通过程序员定义的

计算机只知道你告诉他们的东西。

types of knowledge

  • 陈述性知识

  • 程序性知识(a recipe to “how-to”)——步骤,流程控制,停止方式

computers are machines

类型: 固定程序计算机(e.g.计算器) 和 存储程序计算机(可以执行指令)

1
2
3
4
5
6
//         →  | arithmetic logic Unit(ALU) |
// ← | (do primitive ops) |
// memory → output
// ← input
// → | control unit |
// ← | (program counter) |

stored program computer

  • 存储在计算机内的指令序列(预定义的元指令)
    1) 数学和逻辑
    2) 简单的测试(=,<…)
    3) 移动数据

  • 解释器顺序执行每一条指令(使用测试来改变序列的控制流程,结束时停止)

Basic Primitives

  • 图灵说使用6个元语你就可以计算任何东西了(move left, move right, read, write, scan, do nothing)。
  • 现代的编程语言有着更多的方便的元语集合。
  • 可以通过抽象方法来创建新的元语。
  • 任何可以用一门语言计算得出的,也一定可以用另一门语言计算得出。

Creating Recipes

  • 一门编程语言提供了一个元语操作符的集合
  • 编程语言中,表达式是复杂但合理的元语集合
  • 编程语言中,表单时和计算有价值和意义

Aspect Of Language

  • 元语结构

    • 英语:单词
    • 编程语言: numbers,strings,simple operators
  • 语法

    • 英语: “cat dog boy” 无效语法 – “cat hugs boy” 有效语法
    • 编程语言: “hi”5 无效语法 – 3.2*5 有效语法
  • 静态语义(有意义的有效语法)

    • 英语:”I are hungry”(有效语法但静态语义错误)
    • programming language: 3.2*5 | 3+”hi”(有效语法但静态语义错误)

Aspects Of Language

语义,英语中可能一句话有多个意思,但是编程语言中只有一个意思并且可能不是程序员的本意。

Where Things Go Wrong

  • 语法错误
  • 静态语义错误
  • 和程序员的原本目的不同

Python Programs

  • 程序是定义和命令的序列
  • 命令告诉解释器做什么
  • 可以再shell中或者文件中编写

Objects

  • 程序操作数据对象
  • 对象有一个类型,定义了程序可以对它们做哪些是(人,可以走路…)
  • 两种对象
    • scalar(标量对象),在python中的基本对象(6)
    • non-scalar(非标量对象),具有一些内部结构的对象([5,6,7])

Scalar Objects

int,float,bool,NoneType

可以用type()来看对象的类型。

Type Conversions(CAST)

对象之间可以相互转化

Printing To Console

print()

Expressions

  • 结合对象和操作符组成表达式
  • 一个表达式有一个值(有类型)
  • 一个简单的表达式语法 (<object><operator><object>

Operators On Ints And Floats

+,-,*,/,%,**

Binding Variables And Values

  • 等号把一个值赋值给一个变量名
  • 值存储在电脑内存中
  • 赋值操作把名字和值绑定
  • 与变量名相关联的值可以通过调用变量名重新获取

Abstracting Expressions

为什么要把表达式的值给一个名字?

  • 方便重用
  • 之后改代码容易

Programming vs Math

编程中,你不能“solve for x”(你要告诉计算机怎么做)(等号左边一定是变量,右边一定是表达式,和数学不同)

Changing Bindings

  • 通过重新赋值语句可以重新绑定变量名
  • 先前的值可能还存贮在内存中,但是失去操作(可能最后被垃圾收集器处理)
  • 重新计算之后值才会变化

Shell vs. Editor

(just an execise)

Python vs. Math

(just an execise)

Bindings

(just an execise)

Branching and Iteration

Strings

  • 字母,特殊字符,空格,数字
  • 被包在双引号或单引号中
  • 连接的字符串
  • 进行一些字符串的在python文档中被定义的运算符

Input/Output:print

  • 习惯输出东西来console
  • print关键字

Input/Output:input(“”)

  • 可以打印引号里的一切
  • 用户打一些东西然后敲击enter
  • 把值绑定给变量(text = input(“Type anything…”))
  • 返回一个字符串,如果要作用于数字的话,要类型转化(num = int(input(“Type a number…”)))

Comparision Operations On int, float, string

, >=, <, <=, ==, !=

Logic Operators On bools

not, and, or

Control Flow - Branching

if, if…else…, if…elif…else

使用缩进来表示代码块

Indentation

缩进在Python中很关键

可以嵌套使用分支结构

= VS ==

赋值和等价

Control Flow: while Loops

while, for…in…, for…in range(start, stop, step)

break Statement

  • 立刻退出它所在的循环
  • 跳过代码块中剩下的表达式
  • !只退出最内层的循环

for VS while Loops

for loops while loops
知道迭代次数 循环无限次数
can break can break
使用计数器 使用计数器必须再循环前初始化,再循环内部增加
可以用while loop重写 while loop不一定可以用for loop

Strings

(just an execise)

Comparisons

(just an execise)

Branching

(just an execise)

While Loops

(just an execise)

For Loops

(just an execise)

String Manipulation, Guess and Check, Approximations, Bisection

Strings

  • 把它看作是一个区分大小写的字符序列
  • 可以用 ==,>,<,等来比较字符串
  • 可以使用len()函数来获取被括号包围的字符串的长度
  • 方括号被用来执行一个字符串的序号来获得在这个序号位置的值(python中负数的索引表示倒数第几个)

切片

  • 字符串切片[start:stop:step]
  • 如果给出两个数字[start:stop],那么默认step=1
  • 你也可以省略数字只保留冒号

  • string是“不可变的”——不能被改变(指针指向新的赋值对象)

For Loops Recap

  • for循环有一个循环变量来迭代一系列的值
1
2
3
4
for var in range(4):
# var 迭代值0,1,2,3
<expression>
# expression执行var
  • range是一种数字迭代的方式,但是循环变量可以迭代任何一系列的值,不仅仅是数字

Strings And Loops

1
2
3
4
5
s = "abcdefgh"

for char in s:
if char == 'i' or char == 'u'
print("There is an i or u")

Code Example: Robot Cheerleaders

Algorithms

Guess-And-Check

猜想与验证

Approximate Solusions

  • 比较好的解决方法
  • 以一个猜测开始,然后以一个很小的值递增
  • 如果满足(条件,e.g. sth >= epsilon),就一直猜测下去
  • 减小递增值会减慢程序运行,增加epsilon会让结果减少精确度

Bisection Search(二分法)

  • 每次迭代一半间隔
  • 新的猜测在区间中间

Bisection Search Convergence

  • 搜索空间:
    • 第一次猜想:N/2
    • 第二次猜想:N/4
    • 第k次猜想:N/2的k次方
  • 以$\log_2(N)$速度收敛
  • 二分查找法适用于函数的值在输入值的单调区间中的情况(范围不对肯定找不到呀)

Decomposition,Abstraction,Functions

Good Programming

  • 代码不是写的越多就代表质量好
  • 用功能的数量来衡量好的程序员
  • 介绍functions
  • 理解分解和抽象的机制

Create Structure With Decomposition

  • 在投影的例子中,分解体现在分离的设备
  • 在编程中,分解体现在将代码划分为模块
    • 独立的
    • 用来分解代码
    • 为了可以复用
    • 使代码有组织
    • 是代码清晰
  • 在这节课中,我们用functions实现分解
  • 在接下来的几周,我们用classes实现分解

Supress Details With Abstraction

  • 投影仪的例子中,设备重要的是知道如何使用它,而不是知道如何制造它
  • 在编程中,把一份碎片的代码认为是一个黑盒
    • 不能看到细节
    • 不需要看到细节
    • 不想要看到细节
    • 隐藏冗长的细节
  • 用函数规格或者文档字符串来获取抽象

Functions

  • functions是可重用的代码块
  • 在程序中,只有当functions被调用时,它们才会运行
  • function的特征:
    • 有一个名字
    • 有0个或多个参数
    • 有文档字符串(可选但推荐)
    • 有函数体
    • returns something

How To Write And Call/Invoke A Function

1
2
3
4
5
6
7
8
9
def is_even(i):
"""
Input: i, a positive int
Returns True if i is even, otherwise False
"""
print("inside is_even")
return i%2 == 0

is_even(2)

Variable Scope

  • 形参在函数调用的时候绑定实参的值
  • 进入函数的时候创建了一个新的作用域
  • 作用域是名称到对象的映射

One Warning If No Return Statement

  • 如果没有显示的给出return,python会return none
  • none表示缺了一个值

Functions As Arguments

  • 参数可以是任何类型,甚至函数
1
2
3
4
5
6
7
8
9
10
11
def func_a():
print 'inside func_a'
def func_b(y):
print 'inside func_b'
return y
def func_c(z):
print 'inside func_c'
return z()
print func_a()
print 5 + func_b(2)
print func_c(func_a)

Scope Example

  • 在函数里,可以获得函数外的变量
  • 在函数里,不能改变在函数外定义的变量——可以使用全局变量,但是不赞成

Harder Scope Example

pythontutor

一个详细展示每一步的作用域的软件,还有其他语言的版本

Scope Details

Function calls

Functions as Arguments

Tuples,Lists,Aliasing,Mutability,and Cloning

Today

  • 已经介绍过许多种类型:int,float,bool,string
  • 介绍新的复合数据类型
    • 元组
    • 数列
  • 别名的概念
  • 易变性概念
  • 克隆的概念

Tuples

  • 一个元素的有序集合,可以混合元素类型
  • 不能改变元素的值(和字符串一致,不可变性)
  • 用圆括号表示
1
2
3
4
5
6
7
8
9
10
11
12
13
# 和字符串很类似,只是元素不单单是字符
te = ()
t = (2, "mit", 3)
t[0]
# -> 2
(2, "mit", 3) + (5, 6)
# -> (2, "mit", 3, 5, 6)
t[1:2]
# -> ("mit",),逗号表示是元组,而不仅仅是个字符串
len(t)
# -> 3
t[1] = 4
# tuple是不可变的,所以python不允许这种操作
  • 便于交换变量的值
1
(x, y) = (y, x)
  • 用于从function中返回不止一个值
1
2
3
4
5
def quotient_and_remainder(x, y):
q = x // y
r = x % y
return (q, r)
(quot, rem) = quotient_and_remainder(4, 5)

Manipulating Tuples–aTuple:((), (), ())

Lists

  • 一个元素的有序集合,可以混合元素类型
  • 可以改变元素的值(可变性)
  • 用方括号表示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a_list = []
L = [2, 'a', 4, [1,2]]
len(L)
# 4
L[0]
# 2
L[2]+1
# 5
L[3]
# [1, 2]
L[4]
# error
i = 2
L[i - 1]
# -> L[1] = 'a'

Changing Elements

  • lists是可变的
  • 赋值某一下标的某一元素改变了值
    L = [2, 1, 3]
    L[1] = 5
    L 现在等于 [2, 5, 3],注意这是同一个对象(和之前在内存中指向一个新的对象是不同的)

Iterating Over A List

  • 下标是从0-len(L)-1

Operations On Lists - ADD

  • 在列表尾部加上元素使用L.append(element)
  • 改变了列表
1
2
3
L = [2, 1, 3]
L.append(5)
# [2, 1, 3, 5]

What is the dot?

  • list是Python对象,Python中的一切都是对象
  • 对象有数据
  • 对象有method和function
  • 通过object_name.do_something()来获取信息
  • 之后会有更深的理解

  • 使用连接符,+操作符来合并数组,会返回一个新的数组

  • 使用L.extand(some_list)改变数组
1
2
3
4
5
6
L1 = [2, 1, 3]
L2 = [4, 5, 6]
L3 = L1 + L2
# [2, 1, 3, 4, 5, 6]
L1.extend([0, 6])
# L1 -> [2, 1, 3, 0, 6]

Operations On Lists - Remove

  • 使用del(L[index])来删除指定下标的元素
  • 使用L.pop()来移除列表最后的元素,返回被移除的列表
  • 使用L.remove(element)来移除指定元素
    • 找到这个元素并移除
    • 如果出现多次,移除第一次出现的
    • 如果列表中不存在这个元素,返回error

Convert Lists To Strings And Back

  • 使用list(s)来将字符串转化为数组,返回一个数组包含每一个s中的字符
  • 使用s.split()按字符来分隔字符串,如果没有传入参数,那就按照空格来分隔
  • 使用’’.join(L)来把数组元素编程字符串,引号中可以设置一个字符来加入每个元素中间组成字符串

Other List Operations

  • sort() & sorted()
  • reverse()
1
2
3
4
5
6
7
L = [9, 6, 0, 3]
sorted(L)
# 返回排序好的列表,但是不改变L
L.sort()
# L -> [0, 3, 6, 9]
L.reverse()
# L -> [9, 6, 3, 0]

An Analogy

一个别名的例子。别名拥有的属性是一致的。

Aliases

  • hot加入是warm的别名——改变一个就会改变另一个
  • append()有副作用

Cloning A List

  • 使用chill = cool[:]创建一个新的list并且拷贝list中的每个元素

Sorting List
一个显示直接赋值和拷贝倒一个新的数组中的区别的例子

Lists Of Lists Of Lists

  • 可以数组嵌套
  • 嵌套的数组改动了也具有副作用

Mutation And Iteration Try This In Python Tutor

  • 避免在迭代数组的时候的改变数组
    • 在循环中,数组的索引计数器、出事长度并不会因为你的删除等操作而改变
    • 正确的做法是先进行副本拷贝
1
2
3
4
5
def remove_dups(L1, L2):
L1_copy = L1[:]
for e in L1_copy:
if e in L2:
L1.remove(e)

Tuples

Simple Lists

List Operations

List Aliasing/Mutation

Recursion and Dictionaries

Recursion

递归就是以自我相似的方式重复项目的过程

What Is Recursion

在算法上,是一种分而治之和减而治之的问题解决方案。

  • 把问题简化为同样的问题的更简单的版本

语义上来说,函数调用它本身的一种编程技术

  • 在编程中,不要得到无限循环
    • 确保至少有一个或多个容易解决的基本案例
    • 为了简化大的问题的输入,必须用一些别的输入来解决相同的问题

Iterative Algorithms So Far

  • 循环结构导致迭代的算法
  • 可以通过循环,在每一次迭代中捕获更新一系列状态变量的计算

Multiplication-Iterative Solution

  • a*b相当于a与自身相加b次
  • 通过以下方式捕获状态:
    • 一个迭代数字i从b开始,i<- i-1,到0停止
    • 一个计算值result,result<-result+a
1
2
3
4
5
6
def mult_iter(a, b): 
result = 0
while b > 0:
result += a
b -= 1
return result

Multiplication-Recursive Solution

  • 循环步骤
    • 思考如何把问题化简为更简单的问题
  • 基础案例
    • 把问题减小到有一个基本案例是可以被直接解决的
    • while b=1, a*b=a
1
2
3
4
5
def mult(a, b):
if b == 1:
return a
else
return a + mult(a, b-1)

Factorial

n! = n*(n-1)*(n-2)*(n-3)*...*1

  • 在阶乘中n的基本案例是?
    n=1 -> if n == 1: return 1

  • 如何化简问题?来递归到基本案例

    else: return n*factorial(n-1)

Recursive Function Scope Example

  • 递归作用域举例,讲解如下

Some Observations

使用同一个变量名,但是他们是不同作用域中的不同对象

  • 每一次递归调用,意味着一个函数创建了他自己的作用域
  • 作用域中绑定的变量不被递归调用改变
  • 一旦函数返回值了,控制流回返回到先前的作用域

Iteration vs. Recursion

1
2
3
4
5
6
7
8
9
10
11
def factorial_iter(n):
prod = 1
for i in range(1, n+1):
prod *= i
return prod

def factorial(n):
if n==1:
return 1
else:
return n*factorial(n-1)
  • 递归更简单,更直观易懂
  • 递归对于程序员的观点来说更有效率
  • 递归对于计算机的观点来说并不是更有效率

Inductive Reasoning

  • 我们怎么知道我们的递归代码会起作用?
  • 循环的版本,有循环终止条件
  • 递归的版本,有递归终止条件,知道基本的案例返回结果而不是调用

数学归纳法的思想

Example Of Induction

0+1+2+3+…+n = (n(n+1))/2

证明:
如果n=0,0 = (0(0+1))/2,true
假设n = k,
0+1+2+…+k = (k(k+1))/2,true
那么
0+1+2+…+k+(k+1) = ((k+1)(k+2))/2, true
所以,得证

Relevance To Code

  • 相同的逻辑应用:
1
2
3
4
5
6
7
def mult(a, b):
if b ==1:
# base case
return a
else:
# assume, sth returns an correct answer, then another thing return a correct answer
return a + mult(a, b-1)

另一个递归的例子:河内塔问题

1
2
3
4
5
6
7
8
9
10
11
def printMove(fr, to):
print('move from' + str(fr) + ' to ' + str(to))

def Towers(n, fr, to, spare):
if n == 1:
printMove(fr, to)
else:
# 把n-1个盘子从fr移到暂存, 然后把剩下的一个盘移到to的盘上,最后再把n-1个盘从spare上移到了to(这可以想象成是倒数最后一步,并可以以这个归纳递归)
Towers(n-1, fr, spare, to)
Towers(1, fr, to, spare)
Towers(n-1, spare, to, fr)

Recursion With Multiple Base Cases

  • 斐波那契数字:兔子问题(两个月后才有繁衍能力)

    Month | Females
    ——— | ————
    0 | 1 (小兔子还没繁衍能力,还是1个)
    1 | 1 (小兔子还没繁衍能力,还是1个)
    2 | 2 (1个小兔子,1个成年兔子)
    3 | 3 (2个小兔子,1个成年兔子)
    4 | 5 (3个小兔子,2个成年兔子)
    … | …

    females(n) = females(n-1) + females(n-2)

    在第n个月的时候,females(n-2)个已经成熟的兔子可以生出小兔子,females(n-1)本来的兔子个数

  • 和河内塔问题不同,这种递归有两个参数了

1
2
3
4
5
def fib(x):
if x == 0 or x == 1:
return 1
else:
return fib(x-1) + fib(x-2)

Recursion On Non-numerics

如何判断回文

Solving Recursively?

  1. 只留下字母并统一转化为小写
  2. Base case:长度为0或者1的字符串是回文
    Recursive case:如果第一个字母和最后一个字母相同,中间部分是回文,那么他就是回文

Example 省略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def isPalindrome(s):
def toChars(s):
s = s.lower()
ans = ''
for c in s:
if c in 'abcdefghijklmnopqrstuvwxyz':
ans = ans + c
return ans
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and isPal(s[1:-1])
return isPal(toChars(s))

How To Store Student Info(这里开始讲字典)

  • 迄今为止,可以使用独立的数组来存储每一种信息
1
2
3
names = ['Ana', 'John', 'Denise', 'Katy']
grade = ['B', 'A+', 'A', 'A']
course = ['2.00', '6.0001', '20.002', '9.01']
  • 每一个项目用单独的数组
  • 每一个数组都必须有一样的长度
  • 相同数组下标的信息对应,每一个下标指向不同的人

How To Update/Retrieve Student Info

1
2
3
4
5
def get_grade(student, name_list, grade_list, course_list):
i = name_list.index(student)
grade = grade_list[i]
course = course_list[i]
return (course, grade)
  • 如果有很多不同的信息需要追踪的话就很混乱
  • 必须保持很多数列,并且把它们作为参数传入
  • 通常使用整数作为下标
  • 必须记住name_list的下标

A Better And Cleaner Way - A Dictionary

  • 用直接关心的东西作为下标(并不总是整数)
  • 使用一个数据结构,而不是单独的数组

A dictionary

Key Value
Key 1 Val 1
Key 2 Val 2
Key 3 Val 3
Key 4 Val 4

A Python Dictionary

  • 存储成对出现的数据({key: Val})
1
2
my_dect = {}
grade = {'Ana': 'B', 'John': 'A+', 'Denise': 'A', 'Katy': 'A'}

Dictionary Lookup

  • 和数组的下标很像
  • 使用key来查找
  • 返回和key相关联的值
  • 如果key没有找到,返回error
1
grades['John']

Dictionary Operations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# add
grades['Sylvan'] = 'A'

# test if key in dictionary
'John' in grades

# delete entry
del(grades['Awa'])

# get an iterable that acrs like a tuple of all keys
grades.keys()

# get an iterable that acrs like a tuple of all values
grades.values()

键要求唯一性,并且不可变性:整数,浮点数,字符串,元祖,布尔值

list vs dict

list dict
元素的有序集合 键值匹配
通过整数型下标来查找元素 通过一个item来查找另一个item
有序目录 不保证顺序
下标是一个整数 键可以是任何一个不可变类型

Creating A Dictionary

一个记录歌词频率的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def lyrics_to_frequencies(lyrics):
myDict = {}
for word in lyrics:
if word in myDict:
myDict[word] += 1
else:
myDict[word] = 1
return myDict

def mosy_common_word(freqs):
value = freqs.values()
best = max(values)
word = []
for k in freqs:
if freqs[k] == best:
word.append(k)
return(words, best)

def word_often(freqs, minTimes):
result = []
done = False
while not done:
temp = most_common_words(freqs)
if temp[1] >= minTimes:
result.append(temp)
for w in temp[0]:
del(freqs[w])
else:
done = True
return result

print(word_often())

Inefficient Fibonacci

fib(n) = fib(n-1) + fib(n-2)

1
2
3
4
5
6
7
                fib(5)
↙↘
fib(4) fib(3)
↙↘ ↙↘
fib(3) fib(2) fib(2) fib(1)
↙↘
fib(2) fib(1)

可以看到同一个值重复计算了多遍

Fibonacci With A Dictionary

1
2
3
4
5
6
7
8
9
def fib_efficient(n, d):
if n in d:
return d[n]
else:
ans = fib_efficient(n-1, d) + fib_efficient(n-2, d)
d[n] = ans
return ans
d = {1:1, 2:2}
print(fib_efficient(6, d))

Testing, Debugging, Exceptions, and Assertions

We Aim For High Quality —— An Analogy With Soup

一个编程debug的类比举例

Programing So Far…

会遇到运行的代码和期望的代码不一致的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
                              测试/验证
* 对照规格,比照输入输出
* "It's not working!"
* "How can I break my program?"
--->
防御性编程
* 编写函数规格
* 程序模块化
* 检查输入输出(断言)的条件
--->
调试
* 研究引起错误的事件
* "Why is it not working?"
* "How can I fix my program?"

Classes of Tests

  • 单元测试

    • 验证代码块
    • 测试独立的函数
  • 回归测试

    • 对于找到的bug添加测试
    • 修复的之前的error不会再次引入别的error
  • 集成测试

    • 整个代码有效么?
    • 倾向于即时去做

(这是一个测试循环)

Testing Approaches

  • 关于问题的自然边界的直觉(比如相等时,最大最小)
    • 没有自然边界可以去取随机值测试
  • 黑盒测试——根据规格文档上的测试用例
  • 白盒测试——根据代码的路径写测试用例测试(测试集包含每一段代码路径)
    • 分支的话,包含所有的条件
    • for循环的话,没进入循环,循环一次,循环不止一次
    • while循环的话,和for循环一样,还包含所有退出while循环的可能方法

Print

你随时可以使用Print来debug你的代码。你可以在函数和循环中使用print来确保是否是正确的传递和正确的值在传递。你也可以使用二分法,直到精确定位。

Debugging Steps

  • 研究程序代码
    • 不要怎么错了
    • 问我是怎么得到预期外的值的
  • 科学方法
    • 研究可行的数据
    • 提出假设
    • 可重复试验
    • 简单的例子

Error Message - Easy

一些报错信息分析

Logic Errors - Hard

  • 先思考再写新的代码
  • 画图,休息
  • 橡皮鸭调试发(或者向某人解释代码)

Dos & Donts Of Debugging And Testing

Don’t Do
写整个程序 写一个函数
测试整个程序 测试并调试函数
调试整个程序 重复以上过程
单元测试 -> 回归测试 -> 集成测试
Don’t Do
更改代码 备份代码
记住什么bug 更改代码
测试代码 用注释写下潜在的bug
忘记改哪里了 测试代码
疯了 新旧对比

Other Types Of Exceptions

  • 已经看到过一些普遍的错误类型:…

Dealing With Exceptions

  • python代码提供handlers用于异常处理
1
2
3
4
5
try:
a = int(input("Tell me one number:"))
b = int(input("Tell me another number:"))
except:
print("Bug in user input.")

把你认为可能有异常错误的部分放入try,如果发生异常,有except语句的话,就会执行except中的内容。

Handling Specific Exceptions

  • 不同的except原因来处理特定的异常
1
2
3
4
5
6
7
8
9
10
try:
a = int(input("Tell me one number:"))
b = int(input("Tell me another number:"))
print("a/b = ", a/b)
except ValueError:
print("Could not convert to a number.")
except ZeroDivisionError:
print("Can't divide by zero.")
except:
print("Something won't very wrong.")

运行类似于if,elseif,else

Other Exceptions

  • else:

try部分没有异常的完成时执行

  • finally:

在try,else,except之后执行,即使引发另一个错误或者执行过break,continue,return。适合用于无论发生什么都要使用的清理代码

What To Do With Exceptions?

  • 发现错误的时候做什么?

  • 默默失败

    • 用默认值替代或者仅仅继续运行
    • 坏主意,用户并没有得到warning
  • 返回一个“error”值
    • 选择什么值呢?
    • 为了检测特殊值使代码复杂化
  • 停止
    • in Python: 提出异常
      raise Exception("descriptive string")

Exceptions As Control Flow

  • 错误发生的时候不要返回特殊值,检查是否‘错误值’已经被返回
  • 事实上,当不能产生和函数规格一致的结果时,提出异常(这种情况下并不会返回错误值,而你可以自己提出异常)

raise <exceptionName>(<arguments>)

Example:Raising An Exception

Example Of Exception

Assertion

Example

1
2
3
def avg(grades):
assert not len(grades) == 0, 'no grades data'
return sum(grades)/len(grades)
  • 如果给了grades一个空列表,那么会引起AssertionError
  • 其他的运行ok
  • 一旦引起了断言错误,那么函数将立即终止(只要先决条件不成立,会阻止程序)

Where To Use Assertions?

  • 想要一旦发生bug就停止,清楚知道在哪发生的情况
  • 作为测试的增补
  • 如果用户提供坏的数据输入就引起异常
  • 使用断言是为了:
    • 检查参数和值的类型
    • 检查数据结构的变量
    • 检查返回值的约束条件

Black Box and Glass Box Testing

Errors

Exceptions