angular的lib & npm link用得太郁闷,随便看点不相关的课程快乐一下。
课程资源: 课程资源 视频地址: 视频地址
视频是2016年版的,比较新,所以主要一视频为主。入门课程,看看能不能用来放松心情。
主要的教学内容:knowledge of concepts,programming skill, problem solving。
What is computation what does a computer do 基础: 执行计算,存储结果
计算的类型: 语言内建 和 通过程序员定义的
计算机只知道你告诉他们的东西。
types of knowledge
computers are machines 类型: 固定程序计算机(e.g.计算器) 和 存储程序计算机(可以执行指令)
stored program computer
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文档中被定义的运算符
可以打印引号里的一切
用户打一些东西然后敲击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中负数的索引表示倒数第几个)
切片
For Loops Recap
1 2 3 4 for var in range(4 ): <expression>
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 , "mit" , 3 ) + (5 , 6 ) t[1 :2 ] len(t) t[1 ] = 4
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) L[0 ] L[2 ]+1 L[3 ] L[4 ] i = 2 L[i - 1 ]
Changing Elements
lists是可变的
赋值某一下标的某一元素改变了值 L = [2, 1, 3] L[1] = 5 L 现在等于 [2, 5, 3],注意这是同一个对象(和之前在内存中指向一个新的对象是不同的)
Iterating Over A List
Operations On Lists - ADD
在列表尾部加上元素使用L.append(element)
改变了列表
1 2 3 L = [2 , 1 , 3 ] L.append(5 )
What is the dot?
1 2 3 4 5 6 L1 = [2 , 1 , 3 ] L2 = [4 , 5 , 6 ] L3 = L1 + L2 L1.extend([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.sort() L.reverse()
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
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 : return a else : 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 : 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?
只留下字母并统一转化为小写
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
1 2 my_dect = {} grade = {'Ana' : 'B' , 'John' : 'A+' , 'Denise' : 'A' , 'Katy' : 'A' }
Dictionary Lookup
和数组的下标很像
使用key来查找
返回和key相关联的值
如果key没有找到,返回error
Dictionary Operations 1 2 3 4 5 6 7 8 9 10 11 12 13 14 grades['Sylvan' ] = 'A' 'John' in gradesdel (grades['Awa' ])grades.keys() 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
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
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
try部分没有异常的完成时执行
在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
为正常使用来必力评论功能请激活JavaScript